1  /-
  2  Copyright (c) 2015 Microsoft Corporation. All rights reserved.
  3  Released under Apache 2.0 license as described in the file LICENSE.
  4  Author: Mario Carneiro
  5  
  6  Multisets.
  7  -/
  8  import logic.function order.boolean_algebra
src         └────────────┘ └───────────────────┘
  9    data.equiv.basic data.list.basic data.list.perm data.list.sort data.quot data.string.basic
src    └──────────────┘ └─────────────┘ └────────────┘ └────────────┘ └───────┘ └───────────────┘
 10    algebra.order_functions algebra.group_power algebra.ordered_group
src    └─────────────────────┘ └─────────────────┘ └───────────────────┘
 11    category.traversable.lemmas tactic.interactive
src    └─────────────────────────┘ └────────────────┘
 12    category.traversable.instances category.basic
src    └────────────────────────────┘ └────────────┘
 13  
 14  open list subtype nat lattice
 15  
 16  variables {α : Type*} {β : Type*} {γ : Type*}
 17  
 18  open_locale add_monoid
 19  
 20  /-- `multiset α` is the quotient of `list α` by list permutation. The result
 21    is a type of finite sets with duplicates allowed.  -/
 22  def {u} multiset (α : Type u) : Type u :=
 23  quotient (list.is_setoid α)
id   └──────┘  └────────────┘ 
src  └──────┘  └────────────┘
typ  └──────┘  └────────────┘ 
 24  
 25  namespace multiset
 26  
 27  instance : has_coe (list α) (multiset α) := ⟨quot.mk _⟩
id              └─────┘  └──┘    └──────┘       └─────┘
src             └─────┘  └──┘     └──────┘
typ             └─────┘  └──┘    └──────┘       └─────┘
doc                               └──────┘
 28  
 29  @[simp] theorem quot_mk_to_coe (l : list α) : @eq (multiset α) ⟦l⟧ l := rfl
id                                       └──┘      └┘  └──────┘        └─┘
src                                      └──┘       └┘  └──────┘           └─┘
typ                                      └──┘      └┘  └──────┘        └─┘
doc    └──┘                                             └──────┘
 30  
 31  @[simp] theorem quot_mk_to_coe' (l : list α) : @eq (multiset α) (quot.mk (≈) l) l := rfl
id                                        └──┘      └┘  └──────┘    └─────┘          └─┘
src                                       └──┘       └┘  └──────┘                        └─┘
typ                                       └──┘      └┘  └──────┘    └─────┘          └─┘
doc    └──┘                                              └──────┘
 32  
 33  @[simp] theorem quot_mk_to_coe'' (l : list α) : @eq (multiset α) (quot.mk setoid.r l) l := rfl
id                                         └──┘      └┘  └──────┘    └─────┘ └──────┘       └─┘
src                                        └──┘       └┘  └──────┘             └──────┘         └─┘
typ                                        └──┘      └┘  └──────┘    └─────┘ └──────┘       └─┘
doc    └──┘                                               └──────┘
 34  
 35  @[simp] theorem coe_eq_coe {l₁ l₂ : list α} : (l₁ : multiset α) = l₂ ↔ l₁ ~ l₂ := quotient.eq
id                                       └──┘      └┘   └──────┘    └┘  └┘  └┘    └─────────┘
src                                      └──┘            └──────┘                   └─────────┘
typ                                      └──┘      └┘   └──────┘    └┘  └┘  └┘    └─────────┘
doc    └──┘                                              └──────┘              
 36  
 37  instance has_decidable_eq [decidable_eq α] : decidable_eq (multiset α)
id                              └──────────┘     └──────────┘  └──────┘ 
src                             └──────────┘      └──────────┘  └──────┘
typ                             └──────────┘     └──────────┘  └──────┘ 
doc                                                             └──────┘
 38  | s₁ s₂ := quotient.rec_on_subsingleton₂ s₁ s₂ $ λ l₁ l₂,
id     └┘ └┘    └───────────────────────────┘           └┘ └┘
src             └───────────────────────────┘
typ    └┘ └┘    └───────────────────────────┘           └┘ └┘
 39    decidable_of_iff' _ quotient.eq
id     └───────────────┘   └─────────┘
src    └───────────────┘   └─────────┘
typ    └───────────────┘   └─────────┘
 40  
 41  /- empty multiset -/
 42  
 43  /-- `0 : multiset α` is the empty set -/
 44  protected def zero : multiset α := @nil α
id                        └──────┘      └─┘ 
src                       └──────┘       └─┘
typ                       └──────┘      └─┘ 
doc                       └──────┘
 45  
 46  instance : has_zero (multiset α)   := ⟨multiset.zero⟩
id              └──────┘  └──────┘         └───────────┘
src             └──────┘  └──────┘          └───────────┘
typ             └──────┘  └──────┘         └───────────┘
doc                       └──────┘          └───────────┘
 47  instance : has_emptyc (multiset α) := ⟨0⟩
id              └────────┘  └──────┘ 
src             └────────┘  └──────┘
typ             └────────┘  └──────┘ 
doc                         └──────┘
 48  instance : inhabited (multiset α)  := ⟨0⟩
id              └───────┘  └──────┘ 
src             └───────┘  └──────┘
typ             └───────┘  └──────┘ 
doc                        └──────┘
 49  
 50  @[simp] theorem coe_nil_eq_zero : (@nil α : multiset α) = 0 := rfl
id                                       └─┘    └──────┘         └─┘
src                                      └─┘     └──────┘          └─┘
typ                                      └─┘    └──────┘         └─┘
doc    └──┘                                      └──────┘
 51  @[simp] theorem empty_eq_zero : (∅ : multiset α) = 0 := rfl
id                                       └──────┘         └─┘
src                                      └──────┘          └─┘
typ                                      └──────┘         └─┘
doc    └──┘                               └──────┘
 52  
 53  theorem coe_eq_zero (l : list α) : (l : multiset α) = 0 ↔ l = [] :=
id                            └──┘         └──────┘         └┘
src                           └──┘           └──────┘           └┘
typ                           └──┘         └──────┘         └┘
doc                                          └──────┘
 54  iff.trans coe_eq_coe perm_nil
id   └───────┘ └────────┘ └──────┘
src  └───────┘ └────────┘ └──────┘
typ  └───────┘ └────────┘ └──────┘
 55  
 56  /- cons -/
 57  
 58  /-- `cons a s` is the multiset which contains `s` plus one more
 59    instance of `a`. -/
 60  def cons (a : α) (s : multiset α) : multiset α :=
id                        └──────┘     └──────┘ 
src                        └──────┘      └──────┘
typ                       └──────┘     └──────┘ 
doc                        └──────┘      └──────┘
 61  quot.lift_on s (λ l, (a :: l : multiset α))
id   └──────────┘         └┘    └──────┘ 
src  └──────────┘            └┘     └──────┘
typ  └──────────┘         └┘    └──────┘ 
doc                                 └──────┘
 62    (λ l₁ l₂ p, quot.sound ((perm_cons a).2 p))
id        └┘ └┘   └────────┘   └───────┘    
src                └────────┘   └───────┘   
typ       └┘ └┘   └────────┘   └───────┘    
 63  
 64  notation a :: b := cons a b
id                      └──┘
src                     └──┘
typ                     └──┘
doc                     └──┘
 65  
 66  instance : has_insert α (multiset α) := ⟨cons⟩
id              └────────┘   └──────┘       └──┘
src             └────────┘    └──────┘        └──┘
typ             └────────┘   └──────┘       └──┘
doc                           └──────┘        └──┘
 67  
 68  @[simp] theorem insert_eq_cons (a : α) (s : multiset α) :
id                                              └──────┘ 
src                                              └──────┘
typ                                             └──────┘ 
doc    └──┘                                      └──────┘
 69    insert a s = a::s := rfl
id     └────┘    └┘    └─┘
src    └────┘       └┘     └─┘
typ    └────┘    └┘    └─┘
doc                  └┘
 70  
 71  @[simp] theorem cons_coe (a : α) (l : list α) :
id                                        └──┘ 
src                                        └──┘
typ                                       └──┘ 
doc    └──┘
 72    (a::l : multiset α) = (a::l : list α) := rfl
id      └┘   └──────┘     └┘   └──┘      └─┘
src      └┘    └──────┘       └┘    └──┘       └─┘
typ     └┘   └──────┘     └┘   └──┘      └─┘
doc      └┘    └──────┘
 73  
 74  theorem singleton_coe (a : α) : (a::0 : multiset α) = ([a] : list α) := rfl
id                                   └┘    └──────┘        └──┘      └─┘
src                                    └┘    └──────┘          └──┘       └─┘
typ                                  └┘    └──────┘        └──┘      └─┘
doc                                    └┘    └──────┘
 75  
 76  @[simp] theorem cons_inj_left {a b : α} (s : multiset α) :
id                                               └──────┘ 
src                                               └──────┘
typ                                              └──────┘ 
doc    └──┘                                       └──────┘
 77    a::s = b::s ↔ a = b :=
id     └┘  └┘    
src     └┘    └┘     
typ    └┘  └┘    
doc     └┘     └┘
 78  ⟨quot.induction_on s $ λ l e,
id    └───────────────┘       
src   └───────────────┘
typ   └───────────────┘       
 79    have [a] ++ l ~ [b] ++ l, from quotient.exact e,
id           └┘    └┘        └────────────┘ 
src           └┘      └┘         └────────────┘
typ          └┘    └┘        └────────────┘ 
doc                  
 80    eq_singleton_of_perm $ (perm_app_right_iff _).1 this, congr_arg _⟩
id     └──────────────────┘    └────────────────┘     └──┘  └───────┘
src    └──────────────────┘    └────────────────┘           └───────┘
typ    └──────────────────┘    └────────────────┘     └──┘  └───────┘
 81  
 82  @[simp] theorem cons_inj_right (a : α) : ∀{s t : multiset α}, a::s = a::t ↔ s = t :=
id                                                   └──────┘    └┘  └┘    
src                                                   └──────┘      └┘    └┘     
typ                                                  └──────┘    └┘  └┘    
doc    └──┘                                           └──────┘      └┘     └┘
 83  by rintros ⟨l₁⟩ ⟨l₂⟩; simp [perm_cons]
id                               └───────┘
src     └───────────────┘  └────┘└───────┘└─
typ     └───────────────┘  └────┘└───────┘└─
doc     └───────────────┘  └────┘         └─
txt     └───────────────┘  └────┘         └─
par     └───────────────┘  └────┘         └─
pid            └────────┘               
st     └────────────────────────────────────
 84  
src  
typ  
doc  
txt  
par  
pid  
st   
 85  @[recursor 5] protected theorem induction {p : multiset α → Prop}
id                                                  └──────┘ 
src                                                 └──────┘
typ                                                 └──────┘ 
doc    └──────┘                                     └──────┘
 86    (h₁ : p 0) (h₂ : ∀ ⦃a : α⦄ {s : multiset α}, p s → p (a :: s)) : ∀s, p s :=
id                                   └──────┘           └┘          
src                                    └──────┘                └┘
typ                                  └──────┘           └┘          
doc                                    └──────┘                └┘
 87  by rintros ⟨l⟩; induction l with _ _ ih; [exact h₁, exact h₂ ih]
id                                                 └┘        └┘ └┘
src     └─────────┘  └────────┘ └──────────┘  └────┘    └────┘  
typ     └─────────┘  └────────┘└──────────┘  └────┘└┘  └────┘└┘└┘
doc     └─────────┘  └────────┘ └──────────┘   └────┘    └────┘  
txt     └─────────┘  └────────┘ └──────────┘   └────┘    └────┘  
par     └─────────┘  └────────┘ └──────────┘   └────┘    └────┘  
pid            └──┘            └─────────┘                   
st     └────────────────────────────────────────────────────────────┘
 88  
 89  @[elab_as_eliminator] protected theorem induction_on {p : multiset α → Prop}
id                                                             └──────┘ 
src                                                            └──────┘
typ                                                            └──────┘ 
doc    └────────────────┘                                      └──────┘
 90    (s : multiset α) (h₁ : p 0) (h₂ : ∀ ⦃a : α⦄ {s : multiset α}, p s → p (a :: s)) : p s :=
id          └──────┘                                 └──────┘           └┘       
src         └──────┘                                    └──────┘                └┘
typ         └──────┘                                 └──────┘           └┘       
doc         └──────┘                                    └──────┘                └┘
 91  multiset.induction h₁ h₂ s
id   └────────────────┘ └┘ └┘ 
src  └────────────────┘
typ  └────────────────┘ └┘ └┘ 
 92  
 93  theorem cons_swap (a b : α) (s : multiset α) : a :: b :: s = b :: a :: s :=
id                                   └──────┘      └┘  └┘    └┘  └┘ 
src                                   └──────┘        └┘   └┘      └┘   └┘
typ                                  └──────┘      └┘  └┘    └┘  └┘ 
doc                                   └──────┘        └┘   └┘       └┘   └┘
 94  quot.induction_on s $ λ l, quotient.sound $ perm.swap _ _ _
id   └───────────────┘        └────────────┘   └───────┘
src  └───────────────┘          └────────────┘   └───────┘
typ  └───────────────┘        └────────────┘   └───────┘
 95  
 96  section rec
 97  variables {C : multiset α → Sort*}
id                  └──────┘
src                 └──────┘
typ                 └──────┘
doc                 └──────┘
 98  
 99  /-- Dependent recursor on multisets.
100  
101  TODO: should be @[recursor 6], but then the definition of `multiset.pi` failes with a stack
102  overflow in `whnf`.
103  -/
104  protected def rec
105    (C_0 : C 0)
id            
typ           
106    (C_cons : Πa m, C m → C (a::m))
id                         └┘
src                              └┘
typ                        └┘
doc                              └┘
107    (C_cons_heq : ∀a a' m b, C_cons a (a'::m) (C_cons a' m b) == C_cons a' (a::m) (C_cons a m b))
id                     └┘    └────┘   └┘└┘   └────┘ └┘    └┘ └────┘ └┘  └┘   └────┘   
src                                         └┘                   └┘             └┘
typ                    └┘    └────┘   └┘└┘   └────┘ └┘    └┘ └────┘ └┘  └┘   └────┘   
doc                                         └┘                                  └┘
108    (m : multiset α) : C m :=
id          └──────┘      
src         └──────┘
typ         └──────┘      
doc         └──────┘
109  quotient.hrec_on m (@list.rec α (λl, C ⟦l⟧) C_0 (λa l b, C_cons a ⟦l⟧ b)) $
id   └──────────────┘    └──────┘         └─┘       └────┘   
src  └──────────────┘     └──────┘                                    
typ  └──────────────┘    └──────┘         └─┘       └────┘   
110    assume l l' h,
id             └┘ 
typ            └┘ 
111    list.rec_heq_of_perm h
id     └──────────────────┘ 
src    └──────────────────┘
typ    └──────────────────┘ 
112      (assume a l l' b b' hl, have ⟦l⟧ = ⟦l'⟧, from quot.sound hl, by cc)
id                 └┘  └┘ └┘         └┘       └────────┘ └┘
src                                               └────────┘        └┘
typ                └┘  └┘ └┘         └┘       └────────┘ └┘     └┘
doc                                                                      └┘
txt                                                                      └┘
par                                                                      └┘
st                                                                      └─┘
113      (assume a a' l, C_cons_heq a a' ⟦l⟧)
id                └┘   └────────┘  └┘ 
src                                       
typ               └┘   └────────┘  └┘ 
114  
115  @[elab_as_eliminator]
doc    └────────────────┘
116  protected def rec_on (m : multiset α)
id                             └──────┘ 
src                            └──────┘
typ                            └──────┘ 
doc                            └──────┘
117    (C_0 : C 0)
id            
typ           
118    (C_cons : Πa m, C m → C (a::m))
id                         └┘
src                              └┘
typ                        └┘
doc                              └┘
119    (C_cons_heq : ∀a a' m b, C_cons a (a'::m) (C_cons a' m b) == C_cons a' (a::m) (C_cons a m b)) :
id                     └┘    └────┘   └┘└┘   └────┘ └┘    └┘ └────┘ └┘  └┘   └────┘   
src                                         └┘                   └┘             └┘
typ                    └┘    └────┘   └┘└┘   └────┘ └┘    └┘ └────┘ └┘  └┘   └────┘   
doc                                         └┘                                  └┘
120    C m :=
id      
typ     
121  multiset.rec C_0 C_cons C_cons_heq m
id   └──────────┘ └─┘ └────┘ └────────┘ 
src  └──────────┘
typ  └──────────┘ └─┘ └────┘ └────────┘ 
doc  └──────────┘
122  
123  variables {C_0 : C 0} {C_cons : Πa m, C m → C (a::m)}
id                                              └┘
src                                                  └┘
typ                                             └┘
doc                                                  └┘
124    {C_cons_heq : ∀a a' m b, C_cons a (a'::m) (C_cons a' m b) == C_cons a' (a::m) (C_cons a m b)}
id                     └┘             └┘└┘          └┘    └┘        └┘  └┘            
src                                         └┘                   └┘             └┘
typ                    └┘             └┘└┘          └┘    └┘        └┘  └┘            
doc                                         └┘                                  └┘
125  
126  @[simp] lemma rec_on_0 : @multiset.rec_on α C (0:multiset α) C_0 C_cons C_cons_heq = C_0 :=
id                             └─────────────┘      └──────┘   └─┘ └────┘ └────────┘  └─┘
src                            └─────────────┘        └──────┘                          
typ                            └─────────────┘      └──────┘   └─┘ └────┘ └────────┘  └─┘
doc    └──┘                                           └──────┘
127  rfl
id   └─┘
src  └─┘
typ  └─┘
128  
129  @[simp] lemma rec_on_cons (a : α) (m : multiset α) :
id                                         └──────┘ 
src                                         └──────┘
typ                                        └──────┘ 
doc    └──┘                                 └──────┘
130    (a :: m).rec_on C_0 C_cons C_cons_heq = C_cons a m (m.rec_on C_0 C_cons C_cons_heq) :=
id       └┘  └────┘  └─┘ └────┘ └────────┘  └────┘    └─────┘ └─┘ └────┘ └────────┘
src       └┘   └────┘                                      └─────┘
typ      └┘  └────┘  └─┘ └────┘ └────────┘  └────┘    └─────┘ └─┘ └────┘ └────────┘
doc       └┘
131  quotient.induction_on m $ assume l, rfl
id   └───────────────────┘             └─┘
src  └───────────────────┘               └─┘
typ  └───────────────────┘             └─┘
132  
133  end rec
134  
135  section mem
136  
137  /-- `a ∈ s` means that `a` has nonzero multiplicity in `s`. -/
138  def mem (a : α) (s : multiset α) : Prop :=
id                       └──────┘ 
src                       └──────┘
typ                      └──────┘ 
doc                       └──────┘
139  quot.lift_on s (λ l, a ∈ l) (λ l₁ l₂ (e : l₁ ~ l₂), propext $ mem_of_perm e)
id   └──────────┘              └┘ └┘      └┘  └┘   └─────┘   └─────────┘ 
src  └──────────┘                                      └─────┘   └─────────┘
typ  └──────────┘              └┘ └┘      └┘  └┘   └─────┘   └─────────┘ 
doc                                               
140  
141  instance : has_mem α (multiset α) := ⟨mem⟩
id              └─────┘   └──────┘       └─┘
src             └─────┘    └──────┘        └─┘
typ             └─────┘   └──────┘       └─┘
doc                        └──────┘        └─┘
142  
143  @[simp] lemma mem_coe {a : α} {l : list α} : a ∈ (l : multiset α) ↔ a ∈ l := iff.rfl
id                                     └──┘           └──────┘          └─────┘
src                                     └──┘              └──────┘             └─────┘
typ                                    └──┘           └──────┘          └─────┘
doc    └──┘                                                └──────┘
144  
145  instance decidable_mem [decidable_eq α] (a : α) (s : multiset α) : decidable (a ∈ s) :=
id                           └──────────┘               └──────┘     └───────┘    
src                          └──────────┘                 └──────┘      └───────┘    
typ                          └──────────┘               └──────┘     └───────┘    
doc                                                       └──────┘
146  quot.rec_on_subsingleton s $ list.decidable_mem a
id   └──────────────────────┘    └────────────────┘ 
src  └──────────────────────┘     └────────────────┘
typ  └──────────────────────┘    └────────────────┘ 
147  
148  @[simp] theorem mem_cons {a b : α} {s : multiset α} : a ∈ b :: s ↔ a = b ∨ a ∈ s :=
id                                          └──────┘        └┘         
src                                          └──────┘           └┘            
typ                                         └──────┘        └┘         
doc    └──┘                                  └──────┘            └┘
149  quot.induction_on s $ λ l, iff.rfl
id   └───────────────┘        └─────┘
src  └───────────────┘          └─────┘
typ  └───────────────┘        └─────┘
150  
151  lemma mem_cons_of_mem {a b : α} {s : multiset α} (h : a ∈ s) : a ∈ b :: s :=
id                                       └──────┘                 └┘ 
src                                       └──────┘                      └┘
typ                                      └──────┘                 └┘ 
doc                                       └──────┘                        └┘
152  mem_cons.2 $ or.inr h
id   └──────┘    └────┘ 
src  └──────┘    └────┘
typ  └──────┘    └────┘ 
153  
154  @[simp] theorem mem_cons_self (a : α) (s : multiset α) : a ∈ a :: s :=
id                                             └──────┘        └┘ 
src                                             └──────┘           └┘
typ                                            └──────┘        └┘ 
doc    └──┘                                     └──────┘            └┘
155  mem_cons.2 (or.inl rfl)
id   └──────┘   └────┘ └─┘
src  └──────┘   └────┘ └─┘
typ  └──────┘   └────┘ └─┘
156  
157  theorem exists_cons_of_mem {s : multiset α} {a : α} : a ∈ s → ∃ t, s = a :: t :=
id                                   └──────┘                      └┘ 
src                                  └──────┘                             └┘
typ                                  └──────┘                      └┘ 
doc                                  └──────┘                                 └┘
158  quot.induction_on s $ λ l (h : a ∈ l),
id   └───────────────┘              
src  └───────────────┘                
typ  └───────────────┘              
159  let ⟨l₁, l₂, e⟩ := mem_split h in
id   └─┘  └┘  └┘       └───────┘ 
src                     └───────┘
typ  └─┘  └┘  └┘       └───────┘ 
160  e.symm ▸ ⟨(l₁++l₂ : list α), quot.sound perm_middle⟩
id    └───┘      └┘     └──┘    └────────┘ └─────────┘
src   └───┘      └┘     └──┘     └────────┘ └─────────┘
typ   └───┘      └┘     └──┘    └────────┘ └─────────┘
161  
162  @[simp] theorem not_mem_zero (a : α) : a ∉ (0 : multiset α) := id
id                                                └──────┘      └┘
src                                                 └──────┘       └┘
typ                                               └──────┘      └┘
doc    └──┘                                          └──────┘
163  
164  theorem eq_zero_of_forall_not_mem {s : multiset α} : (∀x, x ∉ s) → s = 0 :=
id                                          └──────┘                
src                                         └──────┘                     
typ                                         └──────┘                
doc                                         └──────┘
165  quot.induction_on s $ λ l H, by rw eq_nil_iff_forall_not_mem.mpr H; refl
id   └───────────────┘               └───────────────────────────┘ 
src  └───────────────┘               └─┘└───────────────────────────┘   └────
typ  └───────────────┘            └─┘└───────────────────────────┘  └────
doc                                  └─┘                                └────
txt                                  └─┘                                └────
par                                  └─┘                                └────
pid                                                                        
st                                  └─────────────────────────────────────────
166  
src  
typ  
doc  
txt  
par  
pid  
st   
167  theorem eq_zero_iff_forall_not_mem {s : multiset α} : s = 0 ↔ ∀ a, a ∉ s :=
id                                           └──────┘                
src                                          └──────┘                   
typ                                          └──────┘                
doc                                          └──────┘
168  ⟨λ h, h.symm ▸ λ _, not_false, eq_zero_of_forall_not_mem⟩
id        └───┘      └───────┘  └───────────────────────┘
src         └───┘       └───────┘  └───────────────────────┘
typ       └───┘      └───────┘  └───────────────────────┘
169  
170  theorem exists_mem_of_ne_zero {s : multiset α} : s ≠ 0 → ∃ a : α, a ∈ s :=
id                                      └──────┘                   
src                                     └──────┘                      
typ                                     └──────┘                   
doc                                     └──────┘
171  quot.induction_on s $ assume l hl,
id   └───────────────┘            └┘
src  └───────────────┘
typ  └───────────────┘            └┘
172    match l, hl with
id             └┘
typ            └┘
173    | [] := assume h, false.elim $ h rfl
id       └┘             └────────┘    └─┘
src      └┘              └────────┘     └─┘
typ      └┘             └────────┘    └─┘
174    | (a :: l) := assume _, ⟨a, by simp⟩
id         └┘              
src         └┘                        └──┘
typ        └┘                       └──┘
doc                                   └──┘
txt                                   └──┘
par                                   └──┘
st                                   └───┘
175    end
176  
177  @[simp] lemma zero_ne_cons {a : α} {m : multiset α} : 0 ≠ a :: m :=
id                                          └──────┘         └┘ 
src                                          └──────┘           └┘
typ                                         └──────┘         └┘ 
doc    └──┘                                  └──────┘            └┘
178  assume h, have a ∈ (0:multiset α), from h.symm ▸ mem_cons_self _ _, not_mem_zero _ this
id                      └──────┘         └───┘  └───────────┘      └──────────┘   └──┘
src                       └──────┘           └───┘  └───────────┘      └──────────┘
typ                     └──────┘         └───┘  └───────────┘      └──────────┘   └──┘
doc                        └──────┘
179  
180  @[simp] lemma cons_ne_zero {a : α} {m : multiset α} : a :: m ≠ 0 := zero_ne_cons.symm
id                                          └──────┘      └┘        └──────────┘└───┘
src                                          └──────┘        └┘         └──────────┘└───┘
typ                                         └──────┘      └┘        └──────────┘└───┘
doc    └──┘                                  └──────┘        └┘
181  
182  lemma cons_eq_cons {a b : α} {as bs : multiset α} :
id                                        └──────┘ 
src                                        └──────┘
typ                                       └──────┘ 
doc                                        └──────┘
183    a :: as = b :: bs ↔ ((a = b ∧ as = bs) ∨ (a ≠ b ∧ ∃cs, as = b :: cs ∧ bs = a :: cs)) :=
id      └┘ └┘   └┘ └┘        └┘  └┘        └┘ └┘   └┘ └┘  └┘   └┘ └┘
src      └┘       └┘                                      └┘           └┘
typ     └┘ └┘   └┘ └┘        └┘  └┘        └┘ └┘   └┘ └┘  └┘   └┘ └┘
doc      └┘        └┘                                                └┘             └┘
184  begin
st   └─────
185    haveI : decidable_eq α := classical.dec_eq α,
id             └──────────┘     └──────────────┘ 
src    └──────┘└──────────┘ └──┘└──────────────┘
typ    └──────┘└──────────┘└──┘└──────────────┘
doc    └──────┘             └──┘                
txt    └──────┘             └──┘                
par    └──────┘             └──┘                
pid         └┘             └──┘                
st   ─────────────────────────────────────────────┘└─
186    split,
src    └───┘
typ    └───┘
doc    └───┘
txt    └───┘
par    └───┘
st   ──────┘└─
187    { assume eq,
src      └───────┘
typ      └───────┘
doc      └───────┘
txt      └───────┘
par      └───────┘
pid      └───────┘
st   ───┘└───────┘└─
188      by_cases a = b,
id                  
src      └───────┘ 
typ      └───────┘
doc      └───────┘  
txt      └───────┘  
par      └───────┘  
pid                
st   ─────────────────┘└─
189      { subst h, simp * at * },
id               
src        └────┘   └──────────┘
typ        └────┘  └──────────┘
doc        └────┘   └──────────┘
txt        └────┘   └──────────┘
par        └────┘   └──────────┘
pid                    └──┘
st   ─────┘└─────┘└────────────┘└┘
190      { have : a ∈ b :: bs, from eq ▸ mem_cons_self _ _,
id                   └┘ └┘       └┘  └───────────┘
src        └─────┘  └┘    └───┘└┘└───────────┘└──┘
typ        └─────┘└┘└┘  └───┘└┘└───────────┘└──┘
doc        └─────┘   └┘    └───┘                └──┘
txt        └─────┘         └───┘                └──┘
par        └─────┘         └───┘                └──┘
pid        └───┘└┘         └───┘                └──┘
st   ───────────────────────┘└───────────────────────────┘└─
191        have : a ∈ bs, by simpa [h],
id                   └┘            
src        └─────┘         └─────┘ 
typ        └─────┘ └┘     └─────┘
doc        └─────┘         └─────┘ 
txt        └─────┘         └─────┘ 
par        └─────┘         └─────┘ 
pid        └───┘└┘               
st   ──────────────────┘              └─
192        rcases exists_cons_of_mem this with ⟨cs, hcs⟩,
id                └────────────────┘ └──┘
src        └─────┘└────────────────┘    └─────────────┘
typ        └─────┘└────────────────┘└──┘└─────────────┘
doc        └─────┘                      └─────────────┘
txt        └─────┘                      └─────────────┘
par        └─────┘                      └─────────────┘
pid                                    └─────────────┘
st   ──────────────────────────────────────────────────┘└─
193        simp [h, hcs],
id                 └─┘
src        └────┘ └┘   
typ        └────┘└┘└─┘
doc        └────┘ └┘   
txt        └────┘ └┘   
par        └────┘ └┘   
pid             └┘   
st   ──────────────────┘└─
194        have : a :: as = b :: a :: cs, by simp [eq, hcs],
id                     └┘           └┘           └┘  └─┘
src        └─────┘                   └────┘└┘└┘   
typ        └─────┘   └┘     └┘     └────┘└┘└┘└─┘
doc        └─────┘                   └────┘  └┘   
txt        └─────┘                   └────┘  └┘   
par        └─────┘                   └────┘  └┘   
pid        └───┘└┘                         └┘   
st   ──────────────────────────────────┘                   └─
195        have : a :: as = a :: b :: cs, by rwa [cons_swap],
id                     └┘           └┘          └───────┘
src        └─────┘                   └───┘└───────┘
typ        └─────┘   └┘     └┘     └───┘└───────┘
doc        └─────┘                   └───┘         
txt        └─────┘                   └───┘         
par        └─────┘                   └───┘         
pid        └───┘└┘                      └┘         
st   ──────────────────────────────────┘          └───────┘└─
196        simpa using this } },
id                     └──┘
src        └──────────┘    
typ        └──────────┘└──┘
doc        └──────────┘    
txt        └──────────┘    
par        └──────────┘    
pid             └────┘    
st   ──────────────────────┘└──┘
197    { assume h,
src      └──────┘
typ      └──────┘
doc      └──────┘
txt      └──────┘
par      └──────┘
pid      └──────┘
st   ───────────┘└─
198      rcases h with ⟨eq₁, eq₂⟩ | ⟨h, cs, eq₁, eq₂⟩,
id              
src      └─────┘ └──────────────────────────────────┘
typ      └─────┘└──────────────────────────────────┘
doc      └─────┘ └──────────────────────────────────┘
txt      └─────┘ └──────────────────────────────────┘
par      └─────┘ └──────────────────────────────────┘
pid             └──────────────────────────────────┘
st   ───────────────────────────────────────────────┘└─
199      { simp * },
src        └─────┘
typ        └─────┘
doc        └─────┘
txt        └─────┘
par        └─────┘
pid            
st   ─────┘└─────┘└┘
200      { simp [*, cons_swap a b] } }
id                  └───────┘  
src        └───────┘└───────┘  └┘
typ        └───────┘└───────┘└┘
doc        └───────┘           └┘
txt        └───────┘           └┘
par        └───────┘           └┘
pid            └──┘           
st   ─────────────────────────────┘└───
201  end
st   ──┘
202  
203  end mem
204  
205  /- subset -/
206  section subset
207  
208  /-- `s ⊆ t` is the lift of the list subset relation. It means that any
209    element with nonzero multiplicity in `s` has nonzero multiplicity in `t`,
210    but it does not imply that the multiplicity of `a` in `s` is less or equal than in `t`;
211    see `s ≤ t` for this relation. -/
212  protected def subset (s t : multiset α) : Prop := ∀ ⦃a : α⦄, a ∈ s → a ∈ t
id                               └──────┘                              
src                              └──────┘                                  
typ                              └──────┘                              
doc                              └──────┘
213  
214  instance : has_subset (multiset α) := ⟨multiset.subset⟩
id              └────────┘  └──────┘       └─────────────┘
src             └────────┘  └──────┘        └─────────────┘
typ             └────────┘  └──────┘       └─────────────┘
doc                         └──────┘        └─────────────┘
215  
216  @[simp] theorem coe_subset {l₁ l₂ : list α} : (l₁ : multiset α) ⊆ l₂ ↔ l₁ ⊆ l₂ := iff.rfl
id                                       └──┘      └┘   └──────┘    └┘  └┘  └┘    └─────┘
src                                      └──┘            └──────┘                   └─────┘
typ                                      └──┘      └┘   └──────┘    └┘  └┘  └┘    └─────┘
doc    └──┘                                              └──────┘
217  
218  @[simp] theorem subset.refl (s : multiset α) : s ⊆ s := λ a h, h
id                                    └──────┘                
src                                   └──────┘        
typ                                   └──────┘                
doc    └──┘                           └──────┘
219  
220  theorem subset.trans {s t u : multiset α} : s ⊆ t → t ⊆ u → s ⊆ u :=
id                                 └──────┘                 
src                                └──────┘                      
typ                                └──────┘                 
doc                                └──────┘
221  λ h₁ h₂ a m, h₂ (h₁ m)
id     └┘ └┘    └┘  └┘ 
typ    └┘ └┘    └┘  └┘ 
222  
223  theorem subset_iff {s t : multiset α} : s ⊆ t ↔ (∀⦃x⦄, x ∈ s → x ∈ t) := iff.rfl
id                             └──────┘                           └─────┘
src                            └──────┘                                   └─────┘
typ                            └──────┘                           └─────┘
doc                            └──────┘
224  
225  theorem mem_of_subset {s t : multiset α} {a : α} (h : s ⊆ t) : a ∈ s → a ∈ t := @h _
id                                └──────┘                                 
src                               └──────┘                                  
typ                               └──────┘                                 
doc                               └──────┘
226  
227  @[simp] theorem zero_subset (s : multiset α) : 0 ⊆ s :=
id                                    └──────┘        
src                                   └──────┘        
typ                                   └──────┘        
doc    └──┘                           └──────┘
228  λ a, (not_mem_nil a).elim
id        └─────────┘  └──┘
src        └─────────┘   └──┘
typ       └─────────┘  └──┘
229  
230  @[simp] theorem cons_subset {a : α} {s t : multiset α} : (a :: s) ⊆ t ↔ a ∈ t ∧ s ⊆ t :=
id                                             └──────┘       └┘            
src                                             └──────┘         └┘                
typ                                            └──────┘       └┘            
doc    └──┘                                     └──────┘         └┘
231  by simp [subset_iff, or_imp_distrib, forall_and_distrib]
id            └────────┘  └────────────┘  └────────────────┘
src     └────┘└────────┘└┘└────────────┘└┘└────────────────┘└─
typ     └────┘└────────┘└┘└────────────┘└┘└────────────────┘└─
doc     └────┘          └┘              └┘                  └─
txt     └────┘          └┘              └┘                  └─
par     └────┘          └┘              └┘                  └─
pid                   └┘              └┘                  
st     └──────────────────────────────────────────────────────
232  
src  
typ  
doc  
txt  
par  
pid  
st   
233  theorem eq_zero_of_subset_zero {s : multiset α} (h : s ⊆ 0) : s = 0 :=
id                                       └──────┘                
src                                      └──────┘                   
typ                                      └──────┘                
doc                                      └──────┘
234  eq_zero_of_forall_not_mem h
id   └───────────────────────┘ 
src  └───────────────────────┘
typ  └───────────────────────┘ 
235  
236  theorem subset_zero {s : multiset α} : s ⊆ 0 ↔ s = 0 :=
id                            └──────┘           
src                           └──────┘              
typ                           └──────┘           
doc                           └──────┘
237  ⟨eq_zero_of_subset_zero, λ xeq, xeq.symm ▸ subset.refl 0⟩
id    └────────────────────┘    └─┘  └─┘└───┘  └─────────┘
src   └────────────────────┘            └───┘  └─────────┘
typ   └────────────────────┘    └─┘  └─┘└───┘  └─────────┘
238  
239  end subset
240  
241  /- multiset order -/
242  
243  /-- `s ≤ t` means that `s` is a sublist of `t` (up to permutation).
244    Equivalently, `s ≤ t` means that `count a s ≤ count a t` for all `a`. -/
245  protected def le (s t : multiset α) : Prop :=
id                           └──────┘ 
src                          └──────┘
typ                          └──────┘ 
doc                          └──────┘
246  quotient.lift_on₂ s t (<+~) $ λ v₁ v₂ w₁ w₂ p₁ p₂,
id   └───────────────┘            └┘ └┘ └┘ └┘ └┘ └┘
src  └───────────────┘     
typ  └───────────────┘            └┘ └┘ └┘ └┘ └┘ └┘
doc                        
247    propext (p₂.subperm_left.trans p₁.subperm_right)
id     └─────┘  └┘└───────────┘└────┘ └┘└────────────┘
src    └─────┘    └───────────┘└────┘   └────────────┘
typ    └─────┘  └┘└───────────┘└────┘ └┘└────────────┘
248  
249  instance : partial_order (multiset α) :=
id              └───────────┘  └──────┘ 
src             └───────────┘  └──────┘
typ             └───────────┘  └──────┘ 
doc                            └──────┘
250  { le          := multiset.le,
id                   └─────────┘
src                  └─────────┘
typ                  └─────────┘
doc                   └─────────┘
251    le_refl     := by rintros ⟨l⟩; exact subperm.refl _,
id                                          └──────────┘
src                      └─────────┘  └────┘└──────────┘└┘
typ                      └─────────┘  └────┘└──────────┘└┘
doc                      └─────────┘  └────┘            └┘
txt                      └─────────┘  └────┘            └┘
par                      └─────────┘  └────┘            └┘
pid                             └──┘                   └┘
st                      └────────────────────────────────┘
252    le_trans    := by rintros ⟨l₁⟩ ⟨l₂⟩ ⟨l₃⟩; exact @subperm.trans _ _ _ _,
id                                                      └───────────┘
src                      └────────────────────┘  └────┘ └───────────┘└──────┘
typ                      └────────────────────┘  └────┘ └───────────┘└──────┘
doc                      └────────────────────┘  └────┘              └──────┘
txt                      └────────────────────┘  └────┘              └──────┘
par                      └────────────────────┘  └────┘              └──────┘
pid                             └─────────────┘                     └──────┘
st                      └───────────────────────────────────────────────────┘
253    le_antisymm := by rintros ⟨l₁⟩ ⟨l₂⟩ h₁ h₂; exact quot.sound (subperm.antisymm h₁ h₂) }
id                                                      └────────┘  └──────────────┘ └┘ └┘
src                      └─────────────────────┘  └────┘└────────┘ └──────────────┘    └┘
typ                      └─────────────────────┘  └────┘└────────┘ └──────────────┘└┘└┘└┘
doc                      └─────────────────────┘  └────┘                               └┘
txt                      └─────────────────────┘  └────┘                               └┘
par                      └─────────────────────┘  └────┘                               └┘
pid                             └──────────────┘                                      
st                      └──────────────────────────────────────────────────────────────────┘
254  
255  theorem subset_of_le {s t : multiset α} : s ≤ t → s ⊆ t :=
id                               └──────┘            
src                              └──────┘               
typ                              └──────┘            
doc                              └──────┘
256  quotient.induction_on₂ s t $ λ l₁ l₂, subset_of_subperm
id   └────────────────────┘       └┘ └┘  └───────────────┘
src  └────────────────────┘                └───────────────┘
typ  └────────────────────┘       └┘ └┘  └───────────────┘
257  
258  theorem mem_of_le {s t : multiset α} {a : α} (h : s ≤ t) : a ∈ s → a ∈ t :=
id                            └──────┘                            
src                           └──────┘                                  
typ                           └──────┘                            
doc                           └──────┘
259  mem_of_subset (subset_of_le h)
id   └───────────┘  └──────────┘ 
src  └───────────┘  └──────────┘
typ  └───────────┘  └──────────┘ 
260  
261  @[simp] theorem coe_le {l₁ l₂ : list α} : (l₁ : multiset α) ≤ l₂ ↔ l₁ <+~ l₂ := iff.rfl
id                                   └──┘      └┘   └──────┘    └┘  └┘ └─┘ └┘    └─────┘
src                                  └──┘            └──────┘            └─┘       └─────┘
typ                                  └──┘      └┘   └──────┘    └┘  └┘ └─┘ └┘    └─────┘
doc    └──┘                                          └──────┘              └─┘
262  
263  @[elab_as_eliminator] theorem le_induction_on {C : multiset α → multiset α → Prop}
id                                                      └──────┘    └──────┘ 
src                                                     └──────┘     └──────┘
typ                                                     └──────┘    └──────┘ 
doc    └────────────────┘                               └──────┘     └──────┘
264    {s t : multiset α} (h : s ≤ t)
id            └──────┘          
src           └──────┘           
typ           └──────┘          
doc           └──────┘
265    (H : ∀ {l₁ l₂ : list α}, l₁ <+ l₂ → C l₁ l₂) : C s t :=
id                     └──┘    └┘ └┘ └┘    └┘ └┘      
src                    └──┘        └┘
typ                    └──┘    └┘ └┘ └┘    └┘ └┘      
266  quotient.induction_on₂ s t (λ l₁ l₂ ⟨l, p, s⟩,
id   └────────────────────┘      └┘ └┘     
src  └────────────────────┘
typ  └────────────────────┘      └┘ └┘     
267    (show ⟦l⟧ = ⟦l₁⟧, from quot.sound p) ▸ H s) h
id              └┘       └────────┘         
src                      └────────┘    
typ             └┘       └────────┘         
268  
269  theorem zero_le (s : multiset α) : 0 ≤ s :=
id                        └──────┘        
src                       └──────┘        
typ                       └──────┘        
doc                       └──────┘
270  quot.induction_on s $ λ l, subperm_of_sublist $ nil_sublist l
id   └───────────────┘        └────────────────┘   └─────────┘ 
src  └───────────────┘          └────────────────┘   └─────────┘
typ  └───────────────┘        └────────────────┘   └─────────┘ 
271  
272  theorem le_zero {s : multiset α} : s ≤ 0 ↔ s = 0 :=
id                        └──────┘           
src                       └──────┘              
typ                       └──────┘           
doc                       └──────┘
273  ⟨λ h, le_antisymm h (zero_le _), le_of_eq⟩
id        └─────────┘   └─────┘     └──────┘
src        └─────────┘    └─────┘     └──────┘
typ       └─────────┘   └─────┘     └──────┘
274  
275  theorem lt_cons_self (s : multiset α) (a : α) : s < a :: s :=
id                             └──────┘               └┘ 
src                            └──────┘                   └┘
typ                            └──────┘               └┘ 
doc                            └──────┘                    └┘
276  quot.induction_on s $ λ l,
id   └───────────────┘      
src  └───────────────┘
typ  └───────────────┘      
277  suffices l <+~ a :: l ∧ (¬l ~ a :: l),
id             └─┘  └┘       └┘ 
src             └─┘   └┘          └┘
typ            └─┘  └┘       └┘ 
doc             └─┘              
278    by simpa [lt_iff_le_and_ne],
id               └──────────────┘
src       └─────┘└──────────────┘
typ       └─────┘└──────────────┘
doc       └─────┘                
txt       └─────┘                
par       └─────┘                
pid                            
st       └───────────────────────┘
279  ⟨subperm_of_sublist (sublist_cons _ _),
id    └────────────────┘  └──────────┘
src   └────────────────┘  └──────────┘
typ   └────────────────┘  └──────────┘
280   λ p, ne_of_lt (lt_succ_self (length l)) (perm_length p)⟩
id        └──────┘  └──────────┘  └────┘     └─────────┘ 
src        └──────┘  └──────────┘  └────┘      └─────────┘
typ       └──────┘  └──────────┘  └────┘     └─────────┘ 
281  
282  
283  theorem le_cons_self (s : multiset α) (a : α) : s ≤ a :: s :=
id                             └──────┘               └┘ 
src                            └──────┘                   └┘
typ                            └──────┘               └┘ 
doc                            └──────┘                    └┘
284  le_of_lt $ lt_cons_self _ _
id   └──────┘   └──────────┘
src  └──────┘   └──────────┘
typ  └──────┘   └──────────┘
285  
286  theorem cons_le_cons_iff (a : α) {s t : multiset α} : a :: s ≤ a :: t ↔ s ≤ t :=
id                                          └──────┘      └┘    └┘     
src                                          └──────┘        └┘      └┘      
typ                                         └──────┘      └┘    └┘     
doc                                          └──────┘        └┘       └┘
287  quotient.induction_on₂ s t $ λ l₁ l₂, subperm_cons a
id   └────────────────────┘       └┘ └┘  └──────────┘ 
src  └────────────────────┘                └──────────┘
typ  └────────────────────┘       └┘ └┘  └──────────┘ 
288  
289  theorem cons_le_cons (a : α) {s t : multiset α} : s ≤ t → a :: s ≤ a :: t :=
id                                      └──────┘           └┘    └┘ 
src                                      └──────┘               └┘      └┘
typ                                     └──────┘           └┘    └┘ 
doc                                      └──────┘                └┘       └┘
290  (cons_le_cons_iff a).2
id    └──────────────┘  
src   └──────────────┘   
typ   └──────────────┘  
291  
292  theorem le_cons_of_not_mem {a : α} {s t : multiset α} (m : a ∉ s) : s ≤ a :: t ↔ s ≤ t :=
id                                            └──────┘                 └┘     
src                                            └──────┘                      └┘      
typ                                           └──────┘                 └┘     
doc                                            └──────┘                        └┘
293  begin
st   └─────
294    refine ⟨_, λ h, le_trans h $ le_cons_self _ _⟩,
id                     └──────┘     └──────────┘
src    └─────┘ └─┘ └──┘└──────┘  └──────────┘└───┘
typ    └─────┘ └─┘ └──┘└──────┘  └──────────┘└───┘
doc    └─────┘ └─┘ └──┘                      └───┘
txt    └─────┘ └─┘ └──┘                      └───┘
par    └─────┘ └─┘ └──┘                      └───┘
pid           └─┘ └──┘                      └───┘
st   ───────────────────────────────────────────────┘└─
295    suffices : ∀ {t'} (_ : s ≤ t') (_ : a ∈ t'), a :: s ≤ t',
id                                                 └┘ 
src    └─────────┘ └─────────┘   └─────┘     └┘  
typ    └─────────┘ └─────────┘   └─────┘    └┘ 
doc    └─────────┘ └─────────┘    └─────┘      └┘  
txt    └─────────┘ └─────────┘    └─────┘          
par    └─────────┘ └─────────┘    └─────┘          
pid    └───────┘└┘ └─────────┘    └─────┘          
st   ─────────────────────────────────────────────────────────┘└─
296    { exact λ h, (cons_le_cons_iff a).1 (this h (mem_cons_self _ _)) },
id                   └──────────────┘      └──┘    └───────────┘
src      └────┘ └──┘ └──────────────┘ └──┘       └───────────┘└─────┘
typ      └────┘ └──┘ └──────────────┘└──┘ └──┘  └───────────┘└─────┘
doc      └────┘ └──┘                  └──┘                    └─────┘
txt      └────┘ └──┘                  └──┘                    └─────┘
par      └────┘ └──┘                  └──┘                    └─────┘
pid            └──┘                  └──┘                    └────┘
st   ───┘└─────────────────────────────────────────────────────────────┘└┘
297    introv h, revert m, refine le_induction_on h _,
id                                └─────────────┘ 
src    └──────┘  └──────┘  └─────┘└─────────────┘ └┘
typ    └──────┘  └──────┘  └─────┘└─────────────┘└┘
doc    └──────┘  └──────┘  └─────┘                └┘
txt    └──────┘  └──────┘  └─────┘                └┘
par    └──────┘  └──────┘  └─────┘                └┘
pid          └┘        └┘                        └┘
st   ─────────┘└────────┘└──────────────────────────┘└─
298    introv s m₁ m₂,
src    └────────────┘
typ    └────────────┘
doc    └────────────┘
txt    └────────────┘
par    └────────────┘
pid          └──────┘
st   ───────────────┘└─
299    rcases mem_split m₂ with ⟨r₁, r₂, rfl⟩,
id            └───────┘ └┘
src    └─────┘└───────┘  └─────────────────┘
typ    └─────┘└───────┘└┘└─────────────────┘
doc    └─────┘           └─────────────────┘
txt    └─────┘           └─────────────────┘
par    └─────┘           └─────────────────┘
pid                     └─────────────────┘
st   ───────────────────────────────────────┘└─
300    exact perm_middle.subperm_left.2 ((subperm_cons _).2 $ subperm_of_sublist $
id           └──────────────────────┘     └──────────┘        └────────────────┘
src    └────┘└──────────────────────┘└─┘  └──────────┘└────┘ └────────────────┘ 
typ    └────┘└──────────────────────┘└─┘  └──────────┘└────┘ └────────────────┘ 
doc    └────┘                        └─┘              └────┘                    
txt    └────┘                        └─┘              └────┘                    
par    └────┘                        └─┘              └────┘                    
pid                                 └─┘              └────┘                    
st   ──────────────────────────────────────────────────────────────────────────────
301      (sublist_or_mem_of_sublist s).resolve_right m₁)
id        └───────────────────────┘                 └┘
src  ───┘ └───────────────────────┘ └──────────────┘  └┘
typ  ───┘ └───────────────────────┘└──────────────┘└┘└┘
doc  ───┘                           └──────────────┘  └┘
txt  ───┘                           └──────────────┘  └┘
par  ───┘                           └──────────────┘  └┘
pid  ───┘                           └──────────────┘  
st   ───────────────────────────────────────────────────┘
302  end
st   └─┘
303  
304  /- cardinality -/
305  
306  /-- The cardinality of a multiset is the sum of the multiplicities
307    of all its elements, or simply the length of the underlying list. -/
308  def card (s : multiset α) : ℕ :=
id                 └──────┘     
src                └──────┘      
typ                └──────┘     
doc                └──────┘
309  quot.lift_on s length $ λ l₁ l₂, perm_length
id   └──────────┘  └────┘     └┘ └┘  └─────────┘
src  └──────────┘   └────┘            └─────────┘
typ  └──────────┘  └────┘     └┘ └┘  └─────────┘
310  
311  @[simp] theorem coe_card (l : list α) : card (l : multiset α) = length l := rfl
id                                 └──┘     └──┘     └──────┘    └────┘     └─┘
src                                └──┘      └──┘      └──────┘     └────┘      └─┘
typ                                └──┘     └──┘     └──────┘    └────┘     └─┘
doc    └──┘                                  └──┘      └──────┘
312  
313  @[simp] theorem card_zero : @card α 0 = 0 := rfl
id                                └──┘          └─┘
src                               └──┘           └─┘
typ                               └──┘          └─┘
doc    └──┘                       └──┘
314  
315  @[simp] theorem card_cons (a : α) (s : multiset α) : card (a :: s) = card s + 1 :=
id                                         └──────┘     └──┘   └┘    └──┘  
src                                         └──────┘      └──┘    └┘     └──┘   
typ                                        └──────┘     └──┘   └┘    └──┘  
doc    └──┘                                 └──────┘      └──┘    └┘      └──┘
316  quot.induction_on s $ λ l, rfl
id   └───────────────┘        └─┘
src  └───────────────┘          └─┘
typ  └───────────────┘        └─┘
317  
318  @[simp] theorem card_singleton (a : α) : card (a::0) = 1 := by simp
id                                           └──┘  └┘   
src                                           └──┘   └┘            └────
typ                                          └──┘  └┘            └────
doc    └──┘                                   └──┘   └┘             └────
txt                                                                 └────
par                                                                 └────
pid                                                                     
st                                                                 └─────
319  
src  
typ  
doc  
txt  
par  
pid  
st   
320  theorem card_le_of_le {s t : multiset α} (h : s ≤ t) : card s ≤ card t :=
id                                └──────┘              └──┘   └──┘ 
src                               └──────┘                 └──┘    └──┘
typ                               └──────┘              └──┘   └──┘ 
doc                               └──────┘                  └──┘     └──┘
321  le_induction_on h $ λ l₁ l₂, length_le_of_sublist
id   └─────────────┘      └┘ └┘  └──────────────────┘
src  └─────────────┘              └──────────────────┘
typ  └─────────────┘      └┘ └┘  └──────────────────┘
322  
323  theorem eq_of_le_of_card_le {s t : multiset α} (h : s ≤ t) : card t ≤ card s → s = t :=
id                                      └──────┘              └──┘   └──┘      
src                                     └──────┘                 └──┘    └──┘       
typ                                     └──────┘              └──┘   └──┘      
doc                                     └──────┘                  └──┘     └──┘
324  le_induction_on h $ λ l₁ l₂ s h₂, congr_arg coe $ eq_of_sublist_of_length_le s h₂
id   └─────────────┘      └┘ └┘  └┘  └───────┘ └─┘   └────────────────────────┘  └┘
src  └─────────────┘                   └───────┘ └─┘   └────────────────────────┘
typ  └─────────────┘      └┘ └┘  └┘  └───────┘ └─┘   └────────────────────────┘  └┘
325  
326  theorem card_lt_of_lt {s t : multiset α} (h : s < t) : card s < card t :=
id                                └──────┘              └──┘   └──┘ 
src                               └──────┘                 └──┘    └──┘
typ                               └──────┘              └──┘   └──┘ 
doc                               └──────┘                  └──┘     └──┘
327  lt_of_not_ge $ λ h₂, ne_of_lt h $ eq_of_le_of_card_le (le_of_lt h) h₂
id   └──────────┘     └┘  └──────┘    └─────────────────┘  └──────┘   └┘
src  └──────────┘         └──────┘     └─────────────────┘  └──────┘
typ  └──────────┘     └┘  └──────┘    └─────────────────┘  └──────┘   └┘
328  
329  theorem lt_iff_cons_le {s t : multiset α} : s < t ↔ ∃ a, a :: s ≤ t :=
id                                 └──────┘            └┘   
src                                └──────┘                 └┘   
typ                                └──────┘            └┘   
doc                                └──────┘                     └┘
330  ⟨quotient.induction_on₂ s t $ λ l₁ l₂ h,
id    └────────────────────┘       └┘ └┘ 
src   └────────────────────┘
typ   └────────────────────┘       └┘ └┘ 
331    subperm.exists_of_length_lt (le_of_lt h) (card_lt_of_lt h),
id     └─────────────────────────┘  └──────┘    └───────────┘ 
src    └─────────────────────────┘  └──────┘     └───────────┘
typ    └─────────────────────────┘  └──────┘    └───────────┘ 
332  λ ⟨a, h⟩, lt_of_lt_of_le (lt_cons_self _ _) h⟩
id           └────────────┘  └──────────┘
src            └────────────┘  └──────────┘
typ          └────────────┘  └──────────┘
333  
334  @[simp] theorem card_eq_zero {s : multiset α} : card s = 0 ↔ s = 0 :=
id                                     └──────┘     └──┘       
src                                    └──────┘      └──┘         
typ                                    └──────┘     └──┘       
doc    └──┘                            └──────┘      └──┘
335  ⟨λ h, (eq_of_le_of_card_le (zero_le _) (le_of_eq h)).symm, λ e, by simp [e]⟩
id         └─────────────────┘  └─────┘     └──────┘   └──┘                
src         └─────────────────┘  └─────┘     └──────┘    └──┘           └────┘ 
typ        └─────────────────┘  └─────┘     └──────┘   └──┘          └────┘
doc                                                                     └────┘ 
txt                                                                     └────┘ 
par                                                                     └────┘ 
pid                                                                          
st                                                                     └───────┘
336  
337  theorem card_pos {s : multiset α} : 0 < card s ↔ s ≠ 0 :=
id                         └──────┘        └──┘    
src                        └──────┘         └──┘      
typ                        └──────┘        └──┘    
doc                        └──────┘          └──┘
338  pos_iff_ne_zero.trans $ not_congr card_eq_zero
id   └─────────────┘└────┘   └───────┘ └──────────┘
src  └─────────────┘└────┘   └───────┘ └──────────┘
typ  └─────────────┘└────┘   └───────┘ └──────────┘
339  
340  theorem card_pos_iff_exists_mem {s : multiset α} : 0 < card s ↔ ∃ a, a ∈ s :=
id                                        └──────┘        └──┘       
src                                       └──────┘         └──┘         
typ                                       └──────┘        └──┘       
doc                                       └──────┘          └──┘
341  quot.induction_on s $ λ l, length_pos_iff_exists_mem
id   └───────────────┘        └───────────────────────┘
src  └───────────────┘          └───────────────────────┘
typ  └───────────────┘        └───────────────────────┘
342  
343  @[elab_as_eliminator] def strong_induction_on {p : multiset α → Sort*} :
id                                                      └──────┘ 
src                                                     └──────┘
typ                                                     └──────┘ 
doc    └────────────────┘                               └──────┘
344    ∀ (s : multiset α), (∀ s, (∀t < s, p t) → p s) → p s
id           └──────┘                           
src           └──────┘             
typ          └──────┘                           
doc           └──────┘
345  | s := λ ih, ih s $ λ t h,
id           └┘  └┘        
typ          └┘  └┘        
346    have card t < card s, from card_lt_of_lt h,
id          └──┘   └──┘         └───────────┘ 
src         └──┘    └──┘         └───────────┘
typ         └──┘   └──┘         └───────────┘ 
doc         └──┘     └──┘
347    strong_induction_on t ih
id     └─────────────────┘  └┘
typ    └─────────────────┘  └┘
348  using_well_founded {rel_tac := λ _ _, `[exact ⟨_, measure_wf card⟩]}
id                                     
src                                          └────┘ └─┘              
typ                                        └────┘ └─┘              
doc                                          └────┘ └─┘              
txt                                          └────┘ └─┘              
par                                          └────┘ └─┘              
pid                                                └─┘              
349  
350  theorem strong_induction_eq {p : multiset α → Sort*}
id                                    └──────┘ 
src                                   └──────┘
typ                                   └──────┘ 
doc                                   └──────┘
351    (s : multiset α) (H) : @strong_induction_on _ p s H =
id          └──────┘          └─────────────────┘      
src         └──────┘           └─────────────────┘         
typ         └──────┘          └─────────────────┘      
doc         └──────┘
352      H s (λ t h, @strong_induction_on _ p t H) :=
id                └─────────────────┘     
src                   └─────────────────┘
typ               └─────────────────┘     
353  by rw [strong_induction_on]
id          └─────────────────┘
src     └──┘└─────────────────┘└─
typ     └──┘└─────────────────┘└─
doc     └──┘                   └─
txt     └──┘                   └─
par     └──┘                   └─
pid       └┘                   
st     └──────────────────────┘
354  
src  
typ  
doc  
txt  
par  
pid  
st   
355  @[elab_as_eliminator] lemma case_strong_induction_on {p : multiset α → Prop}
id                                                             └──────┘ 
src                                                            └──────┘
typ                                                            └──────┘ 
doc    └────────────────┘                                      └──────┘
356    (s : multiset α) (h₀ : p 0) (h₁ : ∀ a s, (∀t ≤ s, p t) → p (a :: s)) : p s :=
id          └──────┘                                       └┘       
src         └──────┘                                                └┘
typ         └──────┘                                       └┘       
doc         └──────┘                                                 └┘
357  multiset.strong_induction_on s $ assume s,
id   └──────────────────────────┘           
src  └──────────────────────────┘
typ  └──────────────────────────┘           
358  multiset.induction_on s (λ _, h₀) $ λ a s _ ih, h₁ _ _ $
id   └───────────────────┘       └┘         └┘  └┘
src  └───────────────────┘
typ  └───────────────────┘       └┘         └┘  └┘
359  λ t h, ih _ $ lt_of_le_of_lt h $ lt_cons_self _ _
id        └┘     └────────────┘    └──────────┘
src                └────────────┘     └──────────┘
typ       └┘     └────────────┘    └──────────┘
360  
361  /- singleton -/
362  @[simp] theorem singleton_eq_singleton (a : α) : singleton a = a::0 := rfl
id                                                   └───────┘   └┘     └─┘
src                                                   └───────┘     └┘     └─┘
typ                                                  └───────┘   └┘     └─┘
doc    └──┘                                                          └┘
363  
364  @[simp] theorem mem_singleton {a b : α} : b ∈ a::0 ↔ b = a := by simp
id                                              └┘     
src                                                └┘              └────
typ                                             └┘            └────
doc    └──┘                                         └┘                └────
txt                                                                   └────
par                                                                   └────
pid                                                                       
st                                                                   └─────
365  
src  
typ  
doc  
txt  
par  
pid  
st   
366  theorem mem_singleton_self (a : α) : a ∈ (a::0 : multiset α) := mem_cons_self _ _
id                                          └┘    └──────┘      └───────────┘
src                                            └┘    └──────┘       └───────────┘
typ                                         └┘    └──────┘      └───────────┘
doc                                             └┘    └──────┘
367  
368  theorem singleton_inj {a b : α} : a::0 = b::0 ↔ a = b := cons_inj_left _
id                                    └┘   └┘         └───────────┘
src                                     └┘    └┘           └───────────┘
typ                                   └┘   └┘         └───────────┘
doc                                     └┘     └┘
369  
370  @[simp] theorem singleton_ne_zero (a : α) : a::0 ≠ 0 :=
id                                              └┘  
src                                               └┘  
typ                                             └┘  
doc    └──┘                                       └┘
371  ne_of_gt (lt_cons_self _ _)
id   └──────┘  └──────────┘
src  └──────┘  └──────────┘
typ  └──────┘  └──────────┘
372  
373  @[simp] theorem singleton_le {a : α} {s : multiset α} : a::0 ≤ s ↔ a ∈ s :=
id                                            └──────┘     └┘       
src                                            └──────┘       └┘        
typ                                           └──────┘     └┘       
doc    └──┘                                    └──────┘       └┘
374  ⟨λ h, mem_of_le h (mem_singleton_self _),
id        └───────┘   └────────────────┘
src        └───────┘    └────────────────┘
typ       └───────┘   └────────────────┘
375   λ h, let ⟨t, e⟩ := exists_cons_of_mem h in e.symm ▸ cons_le_cons _ (zero_le _)⟩
id        └─┘          └────────────────┘      └───┘  └──────────┘    └─────┘
src                      └────────────────┘       └───┘  └──────────┘    └─────┘
typ       └─┘          └────────────────┘      └───┘  └──────────┘    └─────┘
376  
377  theorem card_eq_one {s : multiset α} : card s = 1 ↔ ∃ a, s = a::0 :=
id                            └──────┘     └──┘          └┘
src                           └──────┘      └──┘              └┘
typ                           └──────┘     └──┘          └┘
doc                           └──────┘      └──┘                   └┘
378  ⟨quot.induction_on s $ λ l h,
id    └───────────────┘       
src   └───────────────┘
typ   └───────────────┘       
379    (list.length_eq_one.1 h).imp $ λ a, congr_arg coe,
id      └────────────────┘   └─┘        └───────┘ └─┘
src     └────────────────┘    └─┘         └───────┘ └─┘
typ     └────────────────┘   └─┘        └───────┘ └─┘
380   λ ⟨a, e⟩, e.symm ▸ rfl⟩
id             └───┘  └─┘
src              └───┘  └─┘
typ            └───┘  └─┘
381  
382  /- add -/
383  
384  /-- The sum of two multisets is the lift of the list append operation.
385    This adds the multiplicities of each element,
386    i.e. `count a (s + t) = count a s + count a t`. -/
387  protected def add (s₁ s₂ : multiset α) : multiset α :=
id                              └──────┘     └──────┘ 
src                             └──────┘      └──────┘
typ                             └──────┘     └──────┘ 
doc                             └──────┘      └──────┘
388  quotient.lift_on₂ s₁ s₂ (λ l₁ l₂, ((l₁ ++ l₂ : list α) : multiset α)) $
id   └───────────────┘ └┘ └┘    └┘ └┘    └┘ └┘ └┘   └──┘     └──────┘ 
src  └───────────────┘                      └┘      └──┘      └──────┘
typ  └───────────────┘ └┘ └┘    └┘ └┘    └┘ └┘ └┘   └──┘     └──────┘ 
doc                                                           └──────┘
389    λ v₁ v₂ w₁ w₂ p₁ p₂, quot.sound $ perm_app p₁ p₂
id       └┘ └┘ └┘ └┘ └┘ └┘  └────────┘   └──────┘ └┘ └┘
src                         └────────┘   └──────┘
typ      └┘ └┘ └┘ └┘ └┘ └┘  └────────┘   └──────┘ └┘ └┘
390  
391  instance : has_add (multiset α) := ⟨multiset.add⟩
id              └─────┘  └──────┘       └──────────┘
src             └─────┘  └──────┘        └──────────┘
typ             └─────┘  └──────┘       └──────────┘
doc                      └──────┘        └──────────┘
392  
393  @[simp] theorem coe_add (s t : list α) : (s + t : multiset α) = (s ++ t : list α) := rfl
id                                  └──┘           └──────┘      └┘    └──┘      └─┘
src                                 └──┘              └──────┘        └┘     └──┘       └─┘
typ                                 └──┘           └──────┘      └┘    └──┘      └─┘
doc    └──┘                                            └──────┘
394  
395  protected theorem add_comm (s t : multiset α) : s + t = t + s :=
id                                     └──────┘           
src                                    └──────┘              
typ                                    └──────┘           
doc                                    └──────┘
396  quotient.induction_on₂ s t $ λ l₁ l₂, quot.sound perm_app_comm
id   └────────────────────┘       └┘ └┘  └────────┘ └───────────┘
src  └────────────────────┘                └────────┘ └───────────┘
typ  └────────────────────┘       └┘ └┘  └────────┘ └───────────┘
397  
398  protected theorem zero_add (s : multiset α) : 0 + s = s :=
id                                   └──────┘          
src                                  └──────┘           
typ                                  └──────┘          
doc                                  └──────┘
399  quot.induction_on s $ λ l, rfl
id   └───────────────┘        └─┘
src  └───────────────┘          └─┘
typ  └───────────────┘        └─┘
400  
401  theorem singleton_add (a : α) (s : multiset α) : ↑[a] + s = a::s := rfl
id                                     └──────┘         └┘    └─┘
src                                     └──────┘             └┘     └─┘
typ                                    └──────┘         └┘    └─┘
doc                                     └──────┘                  └┘
402  
403  protected theorem add_le_add_left (s) {t u : multiset α} : s + t ≤ s + u ↔ t ≤ u :=
id                                                └──────┘               
src                                               └──────┘                    
typ                                               └──────┘               
doc                                               └──────┘
404  quotient.induction_on₃ s t u $ λ l₁ l₂ l₃, subperm_app_left _
id   └────────────────────┘        └┘ └┘ └┘  └──────────────┘
src  └────────────────────┘                     └──────────────┘
typ  └────────────────────┘        └┘ └┘ └┘  └──────────────┘
405  
406  protected theorem add_left_cancel (s) {t u : multiset α} (h : s + t = s + u) : t = u :=
id                                                └──────┘                    
src                                               └──────┘                         
typ                                               └──────┘                    
doc                                               └──────┘
407  le_antisymm ((multiset.add_le_add_left _).1 (le_of_eq h))
id   └─────────┘   └──────────────────────┘      └──────┘ 
src  └─────────┘   └──────────────────────┘      └──────┘
typ  └─────────┘   └──────────────────────┘      └──────┘ 
408    ((multiset.add_le_add_left _).1 (le_of_eq h.symm))
id       └──────────────────────┘      └──────┘ └───┘
src      └──────────────────────┘      └──────┘  └───┘
typ      └──────────────────────┘      └──────┘ └───┘
409  
410  instance : ordered_cancel_comm_monoid (multiset α) :=
id              └────────────────────────┘  └──────┘ 
src             └────────────────────────┘  └──────┘
typ             └────────────────────────┘  └──────┘ 
doc                                         └──────┘
411  { zero                  := 0,
412    add                   := (+),
id                              
src                             
typ                             
413    add_comm              := multiset.add_comm,
id                              └───────────────┘
src                             └───────────────┘
typ                             └───────────────┘
414    add_assoc             := λ s₁ s₂ s₃, quotient.induction_on₃ s₁ s₂ s₃ $ λ l₁ l₂ l₃,
id                                └┘ └┘ └┘  └────────────────────┘ └┘ └┘ └┘     └┘ └┘ └┘
src                                         └────────────────────┘
typ                               └┘ └┘ └┘  └────────────────────┘ └┘ └┘ └┘     └┘ └┘ └┘
415      congr_arg coe $ append_assoc l₁ l₂ l₃,
id       └───────┘ └─┘   └──────────┘ └┘ └┘ └┘
src      └───────┘ └─┘   └──────────┘
typ      └───────┘ └─┘   └──────────┘ └┘ └┘ └┘
416    zero_add              := multiset.zero_add,
id                              └───────────────┘
src                             └───────────────┘
typ                             └───────────────┘
417    add_zero              := λ s, by rw [multiset.add_comm, multiset.zero_add],
id                                         └───────────────┘  └───────────────┘
src                                     └──┘└───────────────┘└┘└───────────────┘
typ                                    └──┘└───────────────┘└┘└───────────────┘
doc                                     └──┘                 └┘                 
txt                                     └──┘                 └┘                 
par                                     └──┘                 └┘                 
pid                                       └┘                 └┘                 
st                                     └────────────────────┘└─────────────────┘
418    add_left_cancel       := multiset.add_left_cancel,
id                              └──────────────────────┘
src                             └──────────────────────┘
typ                             └──────────────────────┘
419    add_right_cancel      := λ s₁ s₂ s₃ h, multiset.add_left_cancel s₂ $
id                                └┘ └┘ └┘   └──────────────────────┘ └┘
src                                           └──────────────────────┘
typ                               └┘ └┘ └┘   └──────────────────────┘ └┘
420      by simpa [multiset.add_comm] using h,
id                 └───────────────┘        
src         └─────┘└───────────────┘└──────┘
typ         └─────┘└───────────────┘└──────┘
doc         └─────┘                 └──────┘
txt         └─────┘                 └──────┘
par         └─────┘                 └──────┘
pid                               └────┘
st         └────────────────────────────────┘
421    add_le_add_left       := λ s₁ s₂ h s₃, (multiset.add_le_add_left _).2 h,
id                                └┘ └┘  └┘   └──────────────────────┘     
src                                            └──────────────────────┘   
typ                               └┘ └┘  └┘   └──────────────────────┘     
422    le_of_add_le_add_left := λ s₁ s₂ s₃, (multiset.add_le_add_left _).1,
id                                └┘ └┘ └┘   └──────────────────────┘   
src                                          └──────────────────────┘   
typ                               └┘ └┘ └┘   └──────────────────────┘   
423    ..@multiset.partial_order α }
id        └────────────────────┘ 
src       └────────────────────┘
typ       └────────────────────┘ 
424  
425  @[simp] theorem cons_add (a : α) (s t : multiset α) : a :: s + t = a :: (s + t) :=
id                                          └──────┘      └┘      └┘    
src                                          └──────┘        └┘         └┘    
typ                                         └──────┘      └┘      └┘    
doc    └──┘                                  └──────┘        └┘           └┘
426  by rw [← singleton_add, ← singleton_add, add_assoc]
id            └───────────┘    └───────────┘  └───────┘
src     └────┘└───────────┘└──┘└───────────┘└┘└───────┘└─
typ     └────┘└───────────┘└──┘└───────────┘└┘└───────┘└─
doc     └────┘             └──┘             └┘         └─
txt     └────┘             └──┘             └┘         └─
par     └────┘             └──┘             └┘         └─
pid       └──┘             └──┘             └┘         
st     └──────────────────┘└───────────────┘└─────────┘
427  
src  
typ  
doc  
txt  
par  
pid  
st   
428  @[simp] theorem add_cons (a : α) (s t : multiset α) : s + a :: t = a :: (s + t) :=
id                                          └──────┘        └┘    └┘    
src                                          └──────┘           └┘      └┘    
typ                                         └──────┘        └┘    └┘    
doc    └──┘                                  └──────┘            └┘       └┘
429  by rw [add_comm, cons_add, add_comm]
id          └──────┘  └──────┘  └──────┘
src     └──┘└──────┘└┘└──────┘└┘└──────┘└─
typ     └──┘└──────┘└┘└──────┘└┘└──────┘└─
doc     └──┘        └┘        └┘        └─
txt     └──┘        └┘        └┘        └─
par     └──┘        └┘        └┘        └─
pid       └┘        └┘        └┘        
st     └───────────┘└────────┘└────────┘
430  
src  
typ  
doc  
txt  
par  
pid  
st   
431  theorem le_add_right (s t : multiset α) : s ≤ s + t :=
id                               └──────┘         
src                              └──────┘           
typ                              └──────┘         
doc                              └──────┘
432  by simpa using add_le_add_left (zero_le t) s
id                  └─────────────┘  └─────┘   
src     └──────────┘└─────────────┘ └─────┘ └┘ 
typ     └──────────┘└─────────────┘ └─────┘└┘
doc     └──────────┘                        └┘ 
txt     └──────────┘                        └┘ 
par     └──────────┘                        └┘ 
pid          └────┘                        └┘ 
st     └──────────────────────────────────────────
433  
src  
typ  
doc  
txt  
par  
pid  
st   
434  theorem le_add_left (s t : multiset α) : s ≤ t + s :=
id                              └──────┘         
src                             └──────┘           
typ                             └──────┘         
doc                             └──────┘
435  by simpa using add_le_add_right (zero_le t) s
id                  └──────────────┘  └─────┘   
src     └──────────┘└──────────────┘ └─────┘ └┘ 
typ     └──────────┘└──────────────┘ └─────┘└┘
doc     └──────────┘                         └┘ 
txt     └──────────┘                         └┘ 
par     └──────────┘                         └┘ 
pid          └────┘                         └┘ 
st     └───────────────────────────────────────────
436  
src  
typ  
doc  
txt  
par  
pid  
st   
437  @[simp] theorem card_add (s t : multiset α) : card (s + t) = card s + card t :=
id                                   └──────┘     └──┘       └──┘   └──┘ 
src                                  └──────┘      └──┘         └──┘    └──┘
typ                                  └──────┘     └──┘       └──┘   └──┘ 
doc    └──┘                          └──────┘      └──┘           └──┘     └──┘
438  quotient.induction_on₂ s t length_append
id   └────────────────────┘   └───────────┘
src  └────────────────────┘     └───────────┘
typ  └────────────────────┘   └───────────┘
439  
440  lemma card_smul (s : multiset α) (n : ℕ) :
id                        └──────┘        
src                       └──────┘         
typ                       └──────┘        
doc                       └──────┘
441    (n • s).card = n * s.card :=
id         └──┘     └───┘
src          └──┘       └───┘
typ        └──┘     └───┘
doc           └──┘         └───┘
442  by induction n; simp [succ_smul, *, nat.succ_mul]
id                        └───────┘     └──────────┘
src     └────────┘   └────┘└───────┘└───┘└──────────┘└─
typ     └────────┘  └────┘└───────┘└───┘└──────────┘└─
doc     └────────┘   └────┘         └───┘            └─
txt     └────────┘   └────┘         └───┘            └─
par     └────────┘   └────┘         └───┘            └─
pid                              └───┘            
st     └───────────────────────────────────────────────
443  
src  
typ  
doc  
txt  
par  
pid  
st   
444  @[simp] theorem mem_add {a : α} {s t : multiset α} : a ∈ s + t ↔ a ∈ s ∨ a ∈ t :=
id                                         └──────┘                 
src                                         └──────┘                       
typ                                        └──────┘                 
doc    └──┘                                 └──────┘
445  quotient.induction_on₂ s t $ λ l₁ l₂, mem_append
id   └────────────────────┘       └┘ └┘  └────────┘
src  └────────────────────┘                └────────┘
typ  └────────────────────┘       └┘ └┘  └────────┘
446  
447  theorem le_iff_exists_add {s t : multiset α} : s ≤ t ↔ ∃ u, t = s + u :=
id                                    └──────┘               
src                                   └──────┘                    
typ                                   └──────┘               
doc                                   └──────┘
448  ⟨λ h, le_induction_on h $ λ l₁ l₂ s,
id        └─────────────┘      └┘ └┘ 
src        └─────────────┘
typ       └─────────────┘      └┘ └┘ 
449    let ⟨l, p⟩ := exists_perm_append_of_sublist s in ⟨l, quot.sound p⟩,
id     └─┘         └───────────────────────────┘         └────────┘
src                  └───────────────────────────┘          └────────┘
typ    └─┘         └───────────────────────────┘         └────────┘
450  λ⟨u, e⟩, e.symm ▸ le_add_right s u⟩
id          └───┘  └──────────┘ 
src            └───┘  └──────────┘
typ         └───┘  └──────────┘ 
451  
452  instance : canonically_ordered_monoid (multiset α) :=
id              └────────────────────────┘  └──────┘ 
src             └────────────────────────┘  └──────┘
typ             └────────────────────────┘  └──────┘ 
doc             └────────────────────────┘  └──────┘
453  { lt_of_add_lt_add_left := @lt_of_add_lt_add_left _ _,
id                               └───────────────────┘
src                              └───────────────────┘
typ                              └───────────────────┘
454    le_iff_exists_add     := @le_iff_exists_add _,
id                               └───────────────┘
src                              └───────────────┘
typ                              └───────────────┘
455    bot                   := 0,
456    bot_le                := multiset.zero_le,
id                              └──────────────┘
src                             └──────────────┘
typ                             └──────────────┘
457    ..multiset.ordered_cancel_comm_monoid }
id       └─────────────────────────────────┘
src      └─────────────────────────────────┘
typ      └─────────────────────────────────┘
458  
459  /- repeat -/
460  
461  /-- `repeat a n` is the multiset containing only `a` with multiplicity `n`. -/
462  def repeat (a : α) (n : ℕ) : multiset α := repeat a n
id                              └──────┘     └────┘  
src                              └──────┘      └────┘
typ                             └──────┘     └────┘  
doc                               └──────┘
463  
464  @[simp] lemma repeat_zero (a : α) : repeat a 0 = 0 := rfl
id                                      └────┘          └─┘
src                                      └────┘           └─┘
typ                                     └────┘          └─┘
doc    └──┘                              └────┘
465  
466  @[simp] lemma repeat_succ (a : α) (n) : repeat a (n+1) = a :: repeat a n := by simp [repeat]
id                                          └────┘        └┘ └────┘               └────┘
src                                          └────┘           └┘ └────┘           └────┘└────┘└─
typ                                         └────┘        └┘ └────┘         └────┘└────┘└─
doc    └──┘                                  └────┘             └┘ └────┘           └────┘└────┘└─
txt                                                                                 └────┘      └─
par                                                                                 └────┘      └─
pid                                                                                           
st                                                                                 └──────────────
467  
src  
typ  
doc  
txt  
par  
pid  
st   
468  @[simp] lemma repeat_one (a : α) : repeat a 1 = a :: 0 := by simp
id                                     └────┘      └┘
src                                     └────┘        └┘         └────
typ                                    └────┘      └┘         └────
doc    └──┘                             └────┘         └┘         └────
txt                                                               └────
par                                                               └────
pid                                                                   
st                                                               └─────
469  
src  
typ  
doc  
txt  
par  
pid  
st   
470  @[simp] lemma card_repeat : ∀ (a : α) n, card (repeat a n) = n := length_repeat
id                                          └──┘  └────┘         └───────────┘
src                                           └──┘  └────┘            └───────────┘
typ                                         └──┘  └────┘         └───────────┘
doc    └──┘                                   └──┘  └────┘
471  
472  theorem eq_of_mem_repeat {a b : α} {n} : b ∈ repeat a n → b = a := eq_of_mem_repeat
id                                             └────┘           └──────────────┘
src                                              └────┘               └──────────────┘
typ                                            └────┘           └──────────────┘
doc                                               └────┘
473  
474  theorem eq_repeat' {a : α} {s : multiset α} : s = repeat a s.card ↔ ∀ b ∈ s, b = a :=
id                                  └──────┘       └────┘  └───┘           
src                                  └──────┘         └────┘    └───┘            
typ                                 └──────┘       └────┘  └───┘           
doc                                  └──────┘          └────┘    └───┘
475  quot.induction_on s $ λ l, iff.trans ⟨λ h,
id   └───────────────┘        └───────┘    
src  └───────────────┘          └───────┘
typ  └───────────────┘        └───────┘    
476    (perm_repeat.1 $ (quotient.exact h).symm).symm, congr_arg coe⟩ eq_repeat'
id      └─────────┘     └────────────┘  └──┘  └──┘   └───────┘ └─┘  └────────┘
src     └─────────┘     └────────────┘   └──┘  └──┘   └───────┘ └─┘  └────────┘
typ     └─────────┘     └────────────┘  └──┘  └──┘   └───────┘ └─┘  └────────┘
477  
478  theorem eq_repeat_of_mem {a : α} {s : multiset α} : (∀ b ∈ s, b = a) → s = repeat a s.card :=
id                                        └──────┘                     └────┘  └───┘
src                                        └──────┘                           └────┘    └───┘
typ                                       └──────┘                     └────┘  └───┘
doc                                        └──────┘                             └────┘    └───┘
479  eq_repeat'.2
id   └────────┘
src  └────────┘
typ  └────────┘
480  
481  theorem eq_repeat {a : α} {n} {s : multiset α} : s = repeat a n ↔ card s = n ∧ ∀ b ∈ s, b = a :=
id                                     └──────┘       └────┘    └──┘              
src                                     └──────┘         └────┘      └──┘                  
typ                                    └──────┘       └────┘    └──┘              
doc                                     └──────┘          └────┘       └──┘
482  ⟨λ h, h.symm ▸ ⟨card_repeat _ _, λ b, eq_of_mem_repeat⟩,
id        └───┘   └─────────┘          └──────────────┘
src         └───┘   └─────────┘           └──────────────┘
typ       └───┘   └─────────┘          └──────────────┘
483   λ ⟨e, al⟩, e ▸ eq_repeat_of_mem al⟩
id        └┘      └──────────────┘
src                 └──────────────┘
typ       └┘      └──────────────┘
484  
485  theorem repeat_subset_singleton : ∀ (a : α) n, repeat a n ⊆ a::0 := repeat_subset_singleton
id                                                └────┘    └┘     └─────────────────────┘
src                                                 └────┘       └┘     └─────────────────────┘
typ                                               └────┘    └┘     └─────────────────────┘
doc                                                 └────┘        └┘
486  
487  theorem repeat_le_coe {a : α} {n} {l : list α} : repeat a n ≤ l ↔ list.repeat a n <+ l :=
id                                         └──┘     └────┘      └─────────┘   └┘ 
src                                         └──┘      └────┘         └─────────┘     └┘
typ                                        └──┘     └────┘      └─────────┘   └┘ 
doc                                                   └────┘
488  ⟨λ ⟨l', p, s⟩, (perm_repeat.1 p.symm).symm ▸ s, subperm_of_sublist⟩
id                └─────────┘   └───┘ └──┘      └────────────────┘
src                  └─────────┘   └───┘ └──┘      └────────────────┘
typ               └─────────┘   └───┘ └──┘      └────────────────┘
489  
490  /- range -/
491  
492  /-- `range n` is the multiset lifted from the list `range n`,
493    that is, the set `{0, 1, ..., n-1}`. -/
494  def range (n : ℕ) : multiset ℕ := range n
id                      └──────┘     └───┘ 
src                     └──────┘     └───┘
typ                     └──────┘     └───┘ 
doc                      └──────┘
495  
496  @[simp] theorem range_zero : range 0 = 0 := rfl
id                                └───┘         └─┘
src                               └───┘         └─┘
typ                               └───┘         └─┘
doc    └──┘                       └───┘
497  
498  @[simp] theorem range_succ (n : ℕ) : range (succ n) = n :: range n :=
id                                       └───┘  └──┘     └┘ └───┘ 
src                                      └───┘  └──┘       └┘ └───┘
typ                                      └───┘  └──┘     └┘ └───┘ 
doc    └──┘                               └───┘              └┘ └───┘
499  by rw [range, range_concat, ← coe_add, add_comm]; refl
id          └───┘  └──────────┘    └─────┘  └──────┘
src     └──┘└───┘└┘└──────────┘└──┘└─────┘└┘└──────┘  └────
typ     └──┘└───┘└┘└──────────┘└──┘└─────┘└┘└──────┘  └────
doc     └──┘└───┘└┘            └──┘       └┘          └────
txt     └──┘     └┘            └──┘       └┘          └────
par     └──┘     └┘            └──┘       └┘          └────
pid       └┘     └┘            └──┘       └┘              
st     └────────┘└────────────┘└─────────┘└────────┘└──────
500  
src  
typ  
doc  
txt  
par  
pid  
st   
501  @[simp] theorem card_range (n : ℕ) : card (range n) = n := length_range _
id                                       └──┘  └───┘        └──────────┘
src                                      └──┘  └───┘          └──────────┘
typ                                      └──┘  └───┘        └──────────┘
doc    └──┘                               └──┘  └───┘
502  
503  theorem range_subset {m n : ℕ} : range m ⊆ range n ↔ m ≤ n := range_subset
id                                   └───┘   └───┘         └──────────┘
src                                  └───┘    └───┘            └──────────┘
typ                                  └───┘   └───┘         └──────────┘
doc                                   └───┘     └───┘
504  
505  @[simp] theorem mem_range {m n : ℕ} : m ∈ range n ↔ m < n := mem_range
id                                          └───┘         └───────┘
src                                          └───┘            └───────┘
typ                                         └───┘         └───────┘
doc    └──┘                                    └───┘
506  
507  @[simp] theorem not_mem_range_self {n : ℕ} : n ∉ range n := not_mem_range_self
id                                                 └───┘     └────────────────┘
src                                                 └───┘      └────────────────┘
typ                                                └───┘     └────────────────┘
doc    └──┘                                           └───┘
508  
509  /- erase -/
510  section erase
511  variables [decidable_eq α] {s t : multiset α} {a b : α}
id              └──────────┘           └──────┘
src             └──────────┘           └──────┘
typ             └──────────┘           └──────┘
doc                                    └──────┘
512  
513  /-- `erase s a` is the multiset that subtracts 1 from the
514    multiplicity of `a`. -/
515  def erase (s : multiset α) (a : α) : multiset α :=
id                  └──────┘            └──────┘ 
src                 └──────┘              └──────┘
typ                 └──────┘            └──────┘ 
doc                 └──────┘              └──────┘
516  quot.lift_on s (λ l, (l.erase a : multiset α))
id   └──────────┘        └────┘    └──────┘ 
src  └──────────┘           └────┘     └──────┘
typ  └──────────┘        └────┘    └──────┘ 
doc                                    └──────┘
517    (λ l₁ l₂ p, quot.sound (erase_perm_erase a p))
id        └┘ └┘   └────────┘  └──────────────┘  
src                └────────┘  └──────────────┘
typ       └┘ └┘   └────────┘  └──────────────┘  
518  
519  @[simp] theorem coe_erase (l : list α) (a : α) :
id                                  └──┘        
src                                 └──┘
typ                                 └──┘        
doc    └──┘
520    erase (l : multiset α) a = l.erase a := rfl
id     └───┘     └──────┘     └────┘     └─┘
src    └───┘      └──────┘        └────┘      └─┘
typ    └───┘     └──────┘     └────┘     └─┘
doc    └───┘      └──────┘
521  
522  @[simp] theorem erase_zero (a : α) : (0 : multiset α).erase a = 0 := rfl
id                                            └──────┘  └───┘         └─┘
src                                            └──────┘   └───┘          └─┘
typ                                           └──────┘  └───┘         └─┘
doc    └──┘                                    └──────┘   └───┘
523  
524  @[simp] theorem erase_cons_head (a : α) (s : multiset α) : (a :: s).erase a = s :=
id                                               └──────┘       └┘  └───┘    
src                                               └──────┘         └┘   └───┘    
typ                                              └──────┘       └┘  └───┘    
doc    └──┘                                       └──────┘         └┘   └───┘
525  quot.induction_on s $ λ l, congr_arg coe $ erase_cons_head a l
id   └───────────────┘        └───────┘ └─┘   └─────────────┘  
src  └───────────────┘          └───────┘ └─┘   └─────────────┘
typ  └───────────────┘        └───────┘ └─┘   └─────────────┘  
526  
527  @[simp] theorem erase_cons_tail {a b : α} (s : multiset α) (h : b ≠ a) : (b::s).erase a = b :: s.erase a :=
id                                                 └──────┘               └┘ └───┘     └┘ └────┘ 
src                                                 └──────┘                   └┘  └───┘       └┘  └────┘
typ                                                └──────┘               └┘ └───┘     └┘ └────┘ 
doc    └──┘                                         └──────┘                    └┘  └───┘        └┘  └────┘
528  quot.induction_on s $ λ l, congr_arg coe $ erase_cons_tail l h
id   └───────────────┘        └───────┘ └─┘   └─────────────┘  
src  └───────────────┘          └───────┘ └─┘   └─────────────┘
typ  └───────────────┘        └───────┘ └─┘   └─────────────┘  
529  
530  @[simp] theorem erase_of_not_mem {a : α} {s : multiset α} : a ∉ s → s.erase a = s :=
id                                                └──────┘          └────┘   
src                                                └──────┘              └────┘   
typ                                               └──────┘          └────┘   
doc    └──┘                                        └──────┘               └────┘
531  quot.induction_on s $ λ l h, congr_arg coe $ erase_of_not_mem h
id   └───────────────┘         └───────┘ └─┘   └──────────────┘ 
src  └───────────────┘            └───────┘ └─┘   └──────────────┘
typ  └───────────────┘         └───────┘ └─┘   └──────────────┘ 
532  
533  @[simp] theorem cons_erase {s : multiset α} {a : α} : a ∈ s → a :: s.erase a = s :=
id                                   └──────┘                  └┘ └────┘   
src                                  └──────┘                       └┘  └────┘   
typ                                  └──────┘                  └┘ └────┘   
doc    └──┘                          └──────┘                        └┘  └────┘
534  quot.induction_on s $ λ l h, quot.sound (perm_erase h).symm
id   └───────────────┘         └────────┘  └────────┘  └──┘
src  └───────────────┘            └────────┘  └────────┘   └──┘
typ  └───────────────┘         └────────┘  └────────┘  └──┘
535  
536  theorem le_cons_erase (s : multiset α) (a : α) : s ≤ a :: s.erase a :=
id                              └──────┘               └┘ └────┘ 
src                             └──────┘                   └┘  └────┘
typ                             └──────┘               └┘ └────┘ 
doc                             └──────┘                    └┘  └────┘
537  if h : a ∈ s then le_of_eq (cons_erase h).symm
id   └┘             └──────┘  └────────┘  └──┘
src  └┘               └──────┘  └────────┘   └──┘
typ  └┘             └──────┘  └────────┘  └──┘
538  else by rw erase_of_not_mem h; apply le_cons_self
id              └──────────────┘         └──────────┘
src          └─┘└──────────────┘   └────┘└──────────┘
typ          └─┘└──────────────┘  └────┘└──────────┘
doc          └─┘                   └────┘            
txt          └─┘                   └────┘            
par          └─┘                   └────┘            
pid                                                
st          └──────────────────────────────────────────
539  
src  
typ  
doc  
txt  
par  
pid  
st   
540  theorem erase_add_left_pos {a : α} {s : multiset α} (t) : a ∈ s → (s + t).erase a = s.erase a + t :=
id                                          └──────┘                  └───┘    └────┘   
src                                          └──────┘                       └───┘      └────┘   
typ                                         └──────┘                  └───┘    └────┘   
doc                                          └──────┘                         └───┘       └────┘
541  quotient.induction_on₂ s t $ λ l₁ l₂ h, congr_arg coe $ erase_append_left l₂ h
id   └────────────────────┘       └┘ └┘   └───────┘ └─┘   └───────────────┘ └┘ 
src  └────────────────────┘                  └───────┘ └─┘   └───────────────┘
typ  └────────────────────┘       └┘ └┘   └───────┘ └─┘   └───────────────┘ └┘ 
542  
543  theorem erase_add_right_pos {a : α} (s) {t : multiset α} (h : a ∈ t) : (s + t).erase a = s + t.erase a :=
id                                               └──────┘                  └───┘      └────┘ 
src                                               └──────┘                       └───┘         └────┘
typ                                              └──────┘                  └───┘      └────┘ 
doc                                               └──────┘                         └───┘           └────┘
544  by rw [add_comm, erase_add_left_pos s h, add_comm]
id          └──────┘  └────────────────┘    └──────┘
src     └──┘└──────┘└┘└────────────────┘  └┘└──────┘└─
typ     └──┘└──────┘└┘└────────────────┘└┘└──────┘└─
doc     └──┘        └┘                    └┘        └─
txt     └──┘        └┘                    └┘        └─
par     └──┘        └┘                    └┘        └─
pid       └┘        └┘                    └┘        
st     └───────────┘└──────────────────────┘└────────┘
545  
src  
typ  
doc  
txt  
par  
pid  
st   
546  theorem erase_add_right_neg {a : α} {s : multiset α} (t) : a ∉ s → (s + t).erase a = s + t.erase a :=
id                                           └──────┘                  └───┘      └────┘ 
src                                           └──────┘                       └───┘         └────┘
typ                                          └──────┘                  └───┘      └────┘ 
doc                                           └──────┘                         └───┘           └────┘
547  quotient.induction_on₂ s t $ λ l₁ l₂ h, congr_arg coe $ erase_append_right l₂ h
id   └────────────────────┘       └┘ └┘   └───────┘ └─┘   └────────────────┘ └┘ 
src  └────────────────────┘                  └───────┘ └─┘   └────────────────┘
typ  └────────────────────┘       └┘ └┘   └───────┘ └─┘   └────────────────┘ └┘ 
548  
549  theorem erase_add_left_neg {a : α} (s) {t : multiset α} (h : a ∉ t) : (s + t).erase a = s.erase a + t :=
id                                              └──────┘                  └───┘    └────┘   
src                                              └──────┘                       └───┘      └────┘   
typ                                             └──────┘                  └───┘    └────┘   
doc                                              └──────┘                         └───┘       └────┘
550  by rw [add_comm, erase_add_right_neg s h, add_comm]
id          └──────┘  └─────────────────┘    └──────┘
src     └──┘└──────┘└┘└─────────────────┘  └┘└──────┘└─
typ     └──┘└──────┘└┘└─────────────────┘└┘└──────┘└─
doc     └──┘        └┘                     └┘        └─
txt     └──┘        └┘                     └┘        └─
par     └──┘        └┘                     └┘        └─
pid       └┘        └┘                     └┘        
st     └───────────┘└───────────────────────┘└────────┘
551  
src  
typ  
doc  
txt  
par  
pid  
st   
552  theorem erase_le (a : α) (s : multiset α) : s.erase a ≤ s :=
id                                └──────┘     └────┘   
src                                └──────┘       └────┘   
typ                               └──────┘     └────┘   
doc                                └──────┘       └────┘
553  quot.induction_on s $ λ l, subperm_of_sublist (erase_sublist a l)
id   └───────────────┘        └────────────────┘  └───────────┘  
src  └───────────────┘          └────────────────┘  └───────────┘
typ  └───────────────┘        └────────────────┘  └───────────┘  
554  
555  @[simp] theorem erase_lt {a : α} {s : multiset α} : s.erase a < s ↔ a ∈ s :=
id                                        └──────┘     └────┘       
src                                        └──────┘       └────┘         
typ                                       └──────┘     └────┘       
doc    └──┘                                └──────┘       └────┘
556  ⟨λ h, not_imp_comm.1 erase_of_not_mem (ne_of_lt h),
id        └──────────┘  └──────────────┘  └──────┘ 
src        └──────────┘  └──────────────┘  └──────┘
typ       └──────────┘  └──────────────┘  └──────┘ 
557   λ h, by simpa [h] using lt_cons_self (s.erase a) a⟩
id                          └──────────┘  └─────┘    
src           └─────┘ └──────┘└──────────┘ └─────┘ └┘
typ          └─────┘└──────┘└──────────┘ └─────┘ └┘
doc           └─────┘ └──────┘             └─────┘ └┘
txt           └─────┘ └──────┘                     └┘
par           └─────┘ └──────┘                     └┘
pid                 └────┘                     └┘
st           └─────────────────────────────────────────┘
558  
559  theorem erase_subset (a : α) (s : multiset α) : s.erase a ⊆ s :=
id                                    └──────┘     └────┘   
src                                    └──────┘       └────┘   
typ                                   └──────┘     └────┘   
doc                                    └──────┘       └────┘
560  subset_of_le (erase_le a s)
id   └──────────┘  └──────┘  
src  └──────────┘  └──────┘
typ  └──────────┘  └──────┘  
561  
562  theorem mem_erase_of_ne {a b : α} {s : multiset α} (ab : a ≠ b) : a ∈ s.erase b ↔ a ∈ s :=
id                                         └──────┘                 └────┘     
src                                         └──────┘                      └────┘      
typ                                        └──────┘                 └────┘     
doc                                         └──────┘                        └────┘
563  quot.induction_on s $ λ l, list.mem_erase_of_ne ab
id   └───────────────┘        └──────────────────┘ └┘
src  └───────────────┘          └──────────────────┘
typ  └───────────────┘        └──────────────────┘ └┘
564  
565  theorem mem_of_mem_erase {a b : α} {s : multiset α} : a ∈ s.erase b → a ∈ s :=
id                                          └──────┘       └────┘      
src                                          └──────┘          └────┘       
typ                                         └──────┘       └────┘      
doc                                          └──────┘           └────┘
566  mem_of_subset (erase_subset _ _)
id   └───────────┘  └──────────┘
src  └───────────┘  └──────────┘
typ  └───────────┘  └──────────┘
567  
568  theorem erase_comm (s : multiset α) (a b : α) : (s.erase a).erase b = (s.erase b).erase a :=
id                           └──────┘               └────┘  └───┘     └────┘  └───┘  
src                          └──────┘                  └────┘   └───┘       └────┘   └───┘
typ                          └──────┘               └────┘  └───┘     └────┘  └───┘  
doc                          └──────┘                  └────┘   └───┘        └────┘   └───┘
569  quot.induction_on s $ λ l, congr_arg coe $ l.erase_comm a b
id   └───────────────┘        └───────┘ └─┘   └─────────┘  
src  └───────────────┘          └───────┘ └─┘    └─────────┘
typ  └───────────────┘        └───────┘ └─┘   └─────────┘  
570  
571  theorem erase_le_erase {s t : multiset α} (a : α) (h : s ≤ t) : s.erase a ≤ t.erase a :=
id                                 └──────┘                     └────┘   └────┘ 
src                                └──────┘                          └────┘     └────┘
typ                                └──────┘                     └────┘   └────┘ 
doc                                └──────┘                           └────┘      └────┘
572  le_induction_on h $ λ l₁ l₂ h, subperm_of_sublist (erase_sublist_erase _ h)
id   └─────────────┘      └┘ └┘   └────────────────┘  └─────────────────┘   
src  └─────────────┘                └────────────────┘  └─────────────────┘
typ  └─────────────┘      └┘ └┘   └────────────────┘  └─────────────────┘   
573  
574  theorem erase_le_iff_le_cons {s t : multiset α} {a : α} : s.erase a ≤ t ↔ s ≤ a :: t :=
id                                       └──────┘            └────┘        └┘ 
src                                      └──────┘               └────┘            └┘
typ                                      └──────┘            └────┘        └┘ 
doc                                      └──────┘               └────┘               └┘
575  ⟨λ h, le_trans (le_cons_erase _ _) (cons_le_cons _ h),
id        └──────┘  └───────────┘       └──────────┘   
src        └──────┘  └───────────┘       └──────────┘
typ       └──────┘  └───────────┘       └──────────┘   
576   λ h, if m : a ∈ s
id        └┘       
src        └┘       
typ       └┘       
577    then by rw ← cons_erase m at h; exact (cons_le_cons_iff _).1 h
id                  └────────┘               └──────────────┘      
src            └───┘└────────┘ └───┘  └────┘ └──────────────┘└────┘ 
typ            └───┘└────────┘└───┘  └────┘ └──────────────┘└────┘
doc            └───┘           └───┘  └────┘                 └────┘ 
txt            └───┘           └───┘  └────┘                 └────┘ 
par            └───┘           └───┘  └────┘                 └────┘ 
pid              └─┘           └───┘                        └────┘ 
st            └───────────────────────────────────────────────────────
578    else le_trans (erase_le _ _) ((le_cons_of_not_mem m).1 h)⟩
id          └──────┘  └──────┘        └────────────────┘    
src  ─┘     └──────┘  └──────┘        └────────────────┘   
typ  ─┘     └──────┘  └──────┘        └────────────────┘    
doc  ─┘
txt  ─┘
par  ─┘
pid  ─┘
st   ─┘
579  
580  @[simp] theorem card_erase_of_mem {a : α} {s : multiset α} : a ∈ s → card (s.erase a) = pred (card s) :=
id                                                 └──────┘          └──┘  └────┘    └──┘  └──┘ 
src                                                 └──────┘             └──┘   └────┘     └──┘  └──┘
typ                                                └──────┘          └──┘  └────┘    └──┘  └──┘ 
doc    └──┘                                         └──────┘              └──┘   └────┘            └──┘
581  quot.induction_on s $ λ l, length_erase_of_mem
id   └───────────────┘        └─────────────────┘
src  └───────────────┘          └─────────────────┘
typ  └───────────────┘        └─────────────────┘
582  
583  theorem card_erase_lt_of_mem {a : α} {s : multiset α} : a ∈ s → card (s.erase a) < card s :=
id                                            └──────┘          └──┘  └────┘    └──┘ 
src                                            └──────┘             └──┘   └────┘     └──┘
typ                                           └──────┘          └──┘  └────┘    └──┘ 
doc                                            └──────┘              └──┘   └────┘      └──┘
584  λ h, card_lt_of_lt (erase_lt.mpr h)
id       └───────────┘  └──────┘└──┘ 
src       └───────────┘  └──────┘└──┘
typ      └───────────┘  └──────┘└──┘ 
585  
586  theorem card_erase_le {a : α} {s : multiset α} : card (s.erase a) ≤ card s :=
id                                     └──────┘     └──┘  └────┘    └──┘ 
src                                     └──────┘      └──┘   └────┘     └──┘
typ                                    └──────┘     └──┘  └────┘    └──┘ 
doc                                     └──────┘      └──┘   └────┘      └──┘
587  card_le_of_le (erase_le a s)
id   └───────────┘  └──────┘  
src  └───────────┘  └──────┘
typ  └───────────┘  └──────┘  
588  
589  end erase
590  
591  @[simp] theorem coe_reverse (l : list α) : (reverse l : multiset α) = l :=
id                                    └──┘      └─────┘    └──────┘    
src                                   └──┘       └─────┘     └──────┘    
typ                                   └──┘      └─────┘    └──────┘    
doc    └──┘                                                  └──────┘
592  quot.sound $ reverse_perm _
id   └────────┘   └──────────┘
src  └────────┘   └──────────┘
typ  └────────┘   └──────────┘
593  
594  /- map -/
595  
596  /-- `map f s` is the lift of the list `map` operation. The multiplicity
597    of `b` in `map f s` is the number of `a ∈ s` (counting multiplicity)
598    such that `f a = b`. -/
599  def map (f : α → β) (s : multiset α) : multiset β :=
id                          └──────┘     └──────┘ 
src                           └──────┘      └──────┘
typ                         └──────┘     └──────┘ 
doc                           └──────┘      └──────┘
600  quot.lift_on s (λ l : list α, (l.map f : multiset β))
id   └──────────┘         └──┘    └──┘    └──────┘ 
src  └──────────┘          └──┘      └──┘     └──────┘
typ  └──────────┘         └──┘    └──┘    └──────┘ 
doc                                           └──────┘
601    (λ l₁ l₂ p, quot.sound (perm_map f p))
id        └┘ └┘   └────────┘  └──────┘  
src                └────────┘  └──────┘
typ       └┘ └┘   └────────┘  └──────┘  
602  
603  @[simp] theorem coe_map (f : α → β) (l : list α) : map f ↑l = l.map f := rfl
id                                          └──┘     └─┘    └──┘     └─┘
src                                           └──┘      └─┘       └──┘      └─┘
typ                                         └──┘     └─┘    └──┘     └─┘
doc    └──┘                                             └─┘
604  
605  @[simp] theorem map_zero (f : α → β) : map f 0 = 0 := rfl
id                                        └─┘          └─┘
src                                         └─┘           └─┘
typ                                       └─┘          └─┘
doc    └──┘                                 └─┘
606  
607  @[simp] theorem map_cons (f : α → β) (a s) : map f (a::s) = f a :: map f s :=
id                                              └─┘   └┘     └┘ └─┘  
src                                               └─┘     └┘        └┘ └─┘
typ                                             └─┘   └┘     └┘ └─┘  
doc    └──┘                                       └─┘     └┘         └┘ └─┘
608  quot.induction_on s $ λ l, rfl
id   └───────────────┘        └─┘
src  └───────────────┘          └─┘
typ  └───────────────┘        └─┘
609  
610  @[simp] lemma map_singleton (f : α → β) (a : α) : ({a} : multiset α).map f = {f a} := rfl
id                                                       └──────┘  └─┘          └─┘
src                                                          └──────┘   └─┘             └─┘
typ                                                      └──────┘  └─┘          └─┘
doc    └──┘                                                   └──────┘   └─┘
611  
612  @[simp] theorem map_add (f : α → β) (s t) : map f (s + t) = map f s + map f t :=
id                                             └─┘        └─┘    └─┘  
src                                              └─┘           └─┘      └─┘
typ                                            └─┘        └─┘    └─┘  
doc    └──┘                                      └─┘             └─┘       └─┘
613  quotient.induction_on₂ s t $ λ l₁ l₂, congr_arg coe $ map_append _ _ _
id   └────────────────────┘       └┘ └┘  └───────┘ └─┘   └────────┘
src  └────────────────────┘                └───────┘ └─┘   └────────┘
typ  └────────────────────┘       └┘ └┘  └───────┘ └─┘   └────────┘
614  
615  instance (f : α → β) : is_add_monoid_hom (map f) :=
id                        └───────────────┘  └─┘ 
src                         └───────────────┘  └─┘
typ                       └───────────────┘  └─┘ 
doc                         └───────────────┘  └─┘
616  { map_add := map_add _, map_zero := map_zero _ }
id                └─────┘                └──────┘
src               └─────┘                └──────┘
typ               └─────┘                └──────┘
617  
618  @[simp] theorem mem_map {f : α → β} {b : β} {s : multiset α} :
id                                                 └──────┘ 
src                                                   └──────┘
typ                                                └──────┘ 
doc    └──┘                                           └──────┘
619    b ∈ map f s ↔ ∃ a, a ∈ s ∧ f a = b :=
id       └─┘             
src       └─┘                   
typ      └─┘             
doc        └─┘
620  quot.induction_on s $ λ l, mem_map
id   └───────────────┘        └─────┘
src  └───────────────┘          └─────┘
typ  └───────────────┘        └─────┘
621  
622  @[simp] theorem card_map (f : α → β) (s) : card (map f s) = card s :=
id                                            └──┘  └─┘     └──┘ 
src                                             └──┘  └─┘       └──┘
typ                                           └──┘  └─┘     └──┘ 
doc    └──┘                                     └──┘  └─┘        └──┘
623  quot.induction_on s $ λ l, length_map _ _
id   └───────────────┘        └────────┘
src  └───────────────┘          └────────┘
typ  └───────────────┘        └────────┘
624  
625  @[simp] theorem map_eq_zero {s : multiset α} {f : α → β} : s.map f = 0 ↔ s = 0 :=
id                                    └──────┘               └──┘       
src                                   └──────┘                   └──┘         
typ                                   └──────┘               └──┘       
doc    └──┘                           └──────┘                   └──┘
626  by rw [← multiset.card_eq_zero, multiset.card_map, multiset.card_eq_zero]
id            └───────────────────┘  └───────────────┘  └───────────────────┘
src     └────┘└───────────────────┘└┘└───────────────┘└┘└───────────────────┘└─
typ     └────┘└───────────────────┘└┘└───────────────┘└┘└───────────────────┘└─
doc     └────┘                     └┘                 └┘                     └─
txt     └────┘                     └┘                 └┘                     └─
par     └────┘                     └┘                 └┘                     └─
pid       └──┘                     └┘                 └┘                     
st     └──────────────────────────┘└─────────────────┘└─────────────────────┘
627  
src  
typ  
doc  
txt  
par  
pid  
st   
628  theorem mem_map_of_mem (f : α → β) {a : α} {s : multiset α} (h : a ∈ s) : f a ∈ map f s :=
id                                                └──────┘                 └─┘  
src                                                  └──────┘                      └─┘
typ                                               └──────┘                 └─┘  
doc                                                  └──────┘                        └─┘
629  mem_map.2 ⟨_, h, rfl⟩
id   └─────┘        └─┘
src  └─────┘         └─┘
typ  └─────┘        └─┘
630  
631  @[simp] theorem mem_map_of_inj {f : α → β} (H : function.injective f) {a : α} {s : multiset α} :
id                                                 └────────────────┘               └──────┘ 
src                                                  └────────────────┘                 └──────┘
typ                                                └────────────────┘               └──────┘ 
doc    └──┘                                                                             └──────┘
632    f a ∈ map f s ↔ a ∈ s :=
id        └─┘      
src         └─┘        
typ       └─┘      
doc          └─┘
633  quot.induction_on s $ λ l, mem_map_of_inj H
id   └───────────────┘        └────────────┘ 
src  └───────────────┘          └────────────┘
typ  └───────────────┘        └────────────┘ 
634  
635  @[simp] theorem map_map (g : β → γ) (f : α → β) (s : multiset α) : map g (map f s) = map (g ∘ f) s :=
id                                                    └──────┘     └─┘   └─┘     └─┘      
src                                                       └──────┘      └─┘    └─┘       └─┘    
typ                                                   └──────┘     └─┘   └─┘     └─┘      
doc    └──┘                                               └──────┘      └─┘    └─┘        └─┘
636  quot.induction_on s $ λ l, congr_arg coe $ list.map_map _ _ _
id   └───────────────┘        └───────┘ └─┘   └──────────┘
src  └───────────────┘          └───────┘ └─┘   └──────────┘
typ  └───────────────┘        └───────┘ └─┘   └──────────┘
637  
638  @[simp] theorem map_id (s : multiset α) : map id s = s :=
id                               └──────┘     └─┘ └┘   
src                              └──────┘      └─┘ └┘   
typ                              └──────┘     └─┘ └┘   
doc    └──┘                      └──────┘      └─┘
639  quot.induction_on s $ λ l, congr_arg coe $ map_id _
id   └───────────────┘        └───────┘ └─┘   └────┘
src  └───────────────┘          └───────┘ └─┘   └────┘
typ  └───────────────┘        └───────┘ └─┘   └────┘
640  
641  @[simp] lemma map_id' (s : multiset α) : map (λx, x) s = s := map_id s
id                              └──────┘     └─┘             └────┘ 
src                             └──────┘      └─┘                 └────┘
typ                             └──────┘     └─┘             └────┘ 
doc    └──┘                     └──────┘      └─┘
642  
643  @[simp] theorem map_const (s : multiset α) (b : β) : map (function.const α b) s = repeat b s.card :=
id                                  └──────┘            └─┘  └────────────┘      └────┘  └───┘
src                                 └──────┘              └─┘  └────────────┘         └────┘    └───┘
typ                                 └──────┘            └─┘  └────────────┘      └────┘  └───┘
doc    └──┘                         └──────┘              └─┘                          └────┘    └───┘
644  quot.induction_on s $ λ l, congr_arg coe $ map_const _ _
id   └───────────────┘        └───────┘ └─┘   └───────┘
src  └───────────────┘          └───────┘ └─┘   └───────┘
typ  └───────────────┘        └───────┘ └─┘   └───────┘
645  
646  @[congr] theorem map_congr {f g : α → β} {s : multiset α} : (∀ x ∈ s, f x = g x) → map f s = map g s :=
id                                               └──────┘                     └─┘    └─┘  
src    └───┘                                       └──────┘                            └─┘      └─┘
typ                                              └──────┘                     └─┘    └─┘  
doc    └───┘                                       └──────┘                             └─┘       └─┘
647  quot.induction_on s $ λ l H, congr_arg coe $ map_congr H
id   └───────────────┘         └───────┘ └─┘   └───────┘ 
src  └───────────────┘            └───────┘ └─┘   └───────┘
typ  └───────────────┘         └───────┘ └─┘   └───────┘ 
648  
649  lemma map_hcongr {β' : Type*} {m : multiset α} {f : α → β} {f' : α → β'}
id                                      └──────┘                      └┘
src                                     └──────┘
typ                                     └──────┘                      └┘
doc                                     └──────┘
650    (h : β = β') (hf : ∀a∈m, f a == f' a) : map f m == map f' m :=
id            └┘              └┘ └┘     └─┘   └┘ └─┘ └┘ 
src                                └┘         └─┘     └┘ └─┘
typ           └┘              └┘ └┘     └─┘   └┘ └─┘ └┘ 
doc                                            └─┘        └─┘
651  begin subst h, simp at hf, simp [map_congr hf] end
id                                   └───────┘ └┘
src        └────┘   └────────┘  └────┘└───────┘  └┘
typ        └────┘  └────────┘  └────┘└───────┘└┘└┘
doc        └────┘   └────────┘  └────┘           └┘
txt        └────┘   └────────┘  └────┘           └┘
par        └────┘   └────────┘  └────┘           └┘
pid                    └───┘                 
st   └───────────┘└──────────┘└────────────────────┘└─┘
652  
653  theorem eq_of_mem_map_const {b₁ b₂ : β} {l : list α} (h : b₁ ∈ map (function.const α b₂) l) : b₁ = b₂ :=
id                                               └──┘        └┘  └─┘  └────────────┘  └┘      └┘  └┘
src                                               └──┘             └─┘  └────────────┘               
typ                                              └──┘        └┘  └─┘  └────────────┘  └┘      └┘  └┘
doc                                                                 └─┘
654  eq_of_mem_repeat $ by rwa map_const at h
id   └──────────────┘          └───────┘
src  └──────────────┘      └──┘└───────┘└─────
typ  └──────────────┘      └──┘└───────┘└─────
doc                        └──┘         └─────
txt                        └──┘         └─────
par                        └──┘         └─────
pid                                    └───┘
st                        └───────────────────
655  
src  
typ  
doc  
txt  
par  
pid  
st   
656  @[simp] theorem map_le_map {f : α → β} {s t : multiset α} (h : s ≤ t) : map f s ≤ map f t :=
id                                               └──────┘              └─┘    └─┘  
src                                                └──────┘                 └─┘      └─┘
typ                                              └──────┘              └─┘    └─┘  
doc    └──┘                                        └──────┘                  └─┘       └─┘
657  le_induction_on h $ λ l₁ l₂ h, subperm_of_sublist $ map_sublist_map f h
id   └─────────────┘      └┘ └┘   └────────────────┘   └─────────────┘  
src  └─────────────┘                └────────────────┘   └─────────────┘
typ  └─────────────┘      └┘ └┘   └────────────────┘   └─────────────┘  
658  
659  @[simp] theorem map_subset_map {f : α → β} {s t : multiset α} (H : s ⊆ t) : map f s ⊆ map f t :=
id                                                   └──────┘              └─┘    └─┘  
src                                                    └──────┘                 └─┘      └─┘
typ                                                  └──────┘              └─┘    └─┘  
doc    └──┘                                            └──────┘                  └─┘       └─┘
660  λ b m, let ⟨a, h, e⟩ := mem_map.1 m in mem_map.2 ⟨a, H h, e⟩
id        └─┘           └─────┘      └─────┘      
src                          └─────┘       └─────┘
typ       └─┘           └─────┘      └─────┘      
661  
662  /- fold -/
663  
664  /-- `foldl f H b s` is the lift of the list operation `foldl f b l`,
665    which folds `f` over the multiset. It is well defined when `f` is right-commutative,
666    that is, `f (f b a₁) a₂ = f (f b a₂) a₁`. -/
667  def foldl (f : β → α → β) (H : right_commutative f) (b : β) (s : multiset α) : β :=
id                               └───────────────┘               └──────┘     
src                                 └───────────────┘                 └──────┘
typ                              └───────────────┘               └──────┘     
doc                                                                   └──────┘
668  quot.lift_on s (λ l, foldl f b l)
id   └──────────┘       └───┘   
src  └──────────┘         └───┘
typ  └──────────┘       └───┘   
669    (λ l₁ l₂ p, foldl_eq_of_perm H p b)
id        └┘ └┘   └──────────────┘   
src                └──────────────┘
typ       └┘ └┘   └──────────────┘   
670  
671  @[simp] theorem foldl_zero (f : β → α → β) (H b) : foldl f H b 0 = b := rfl
id                                                   └───┘           └─┘
src                                                     └───┘               └─┘
typ                                                  └───┘           └─┘
doc    └──┘                                             └───┘
672  
673  @[simp] theorem foldl_cons (f : β → α → β) (H b a s) : foldl f H b (a :: s) = foldl f H (f b a) s :=
id                                                       └───┘      └┘    └───┘        
src                                                         └───┘          └┘     └───┘
typ                                                      └───┘      └┘    └───┘        
doc    └──┘                                                 └───┘          └┘      └───┘
674  quot.induction_on s $ λ l, rfl
id   └───────────────┘        └─┘
src  └───────────────┘          └─┘
typ  └───────────────┘        └─┘
675  
676  @[simp] theorem foldl_add (f : β → α → β) (H b s t) : foldl f H b (s + t) = foldl f H (foldl f H b s) t :=
id                                                      └───┘          └───┘    └───┘      
src                                                        └───┘               └───┘      └───┘
typ                                                     └───┘          └───┘    └───┘      
doc    └──┘                                                └───┘                 └───┘      └───┘
677  quotient.induction_on₂ s t $ λ l₁ l₂, foldl_append _ _ _ _
id   └────────────────────┘       └┘ └┘  └──────────┘
src  └────────────────────┘                └──────────┘
typ  └────────────────────┘       └┘ └┘  └──────────┘
678  
679  /-- `foldr f H b s` is the lift of the list operation `foldr f b l`,
680    which folds `f` over the multiset. It is well defined when `f` is left-commutative,
681    that is, `f a₁ (f a₂ b) = f a₂ (f a₁ b)`. -/
682  def foldr (f : α → β → β) (H : left_commutative f) (b : β) (s : multiset α) : β :=
id                               └──────────────┘               └──────┘     
src                                 └──────────────┘                 └──────┘
typ                              └──────────────┘               └──────┘     
doc                                                                  └──────┘
683  quot.lift_on s (λ l, foldr f b l)
id   └──────────┘       └───┘   
src  └──────────┘         └───┘
typ  └──────────┘       └───┘   
684    (λ l₁ l₂ p, foldr_eq_of_perm H p b)
id        └┘ └┘   └──────────────┘   
src                └──────────────┘
typ       └┘ └┘   └──────────────┘   
685  
686  @[simp] theorem foldr_zero (f : α → β → β) (H b) : foldr f H b 0 = b := rfl
id                                                   └───┘           └─┘
src                                                     └───┘               └─┘
typ                                                  └───┘           └─┘
doc    └──┘                                             └───┘
687  
688  @[simp] theorem foldr_cons (f : α → β → β) (H b a s) : foldr f H b (a :: s) = f a (foldr f H b s) :=
id                                                       └───┘      └┘       └───┘    
src                                                         └───┘          └┘          └───┘
typ                                                      └───┘      └┘       └───┘    
doc    └──┘                                                 └───┘          └┘           └───┘
689  quot.induction_on s $ λ l, rfl
id   └───────────────┘        └─┘
src  └───────────────┘          └─┘
typ  └───────────────┘        └─┘
690  
691  @[simp] theorem foldr_add (f : α → β → β) (H b s t) : foldr f H b (s + t) = foldr f H (foldr f H b t) s :=
id                                                      └───┘          └───┘    └───┘      
src                                                        └───┘               └───┘      └───┘
typ                                                     └───┘          └───┘    └───┘      
doc    └──┘                                                └───┘                 └───┘      └───┘
692  quotient.induction_on₂ s t $ λ l₁ l₂, foldr_append _ _ _ _
id   └────────────────────┘       └┘ └┘  └──────────┘
src  └────────────────────┘                └──────────┘
typ  └────────────────────┘       └┘ └┘  └──────────┘
693  
694  @[simp] theorem coe_foldr (f : α → β → β) (H : left_commutative f) (b : β) (l : list α) :
id                                               └──────────────┘               └──┘ 
src                                                 └──────────────┘                 └──┘
typ                                              └──────────────┘               └──┘ 
doc    └──┘
695    foldr f H b l = l.foldr f b := rfl
id     └───┘      └────┘      └─┘
src    └───┘           └────┘        └─┘
typ    └───┘      └────┘      └─┘
doc    └───┘
696  
697  @[simp] theorem coe_foldl (f : β → α → β) (H : right_commutative f) (b : β) (l : list α) :
id                                               └───────────────┘               └──┘ 
src                                                 └───────────────┘                 └──┘
typ                                              └───────────────┘               └──┘ 
doc    └──┘
698    foldl f H b l = l.foldl f b := rfl
id     └───┘      └────┘      └─┘
src    └───┘           └────┘        └─┘
typ    └───┘      └────┘      └─┘
doc    └───┘
699  
700  theorem coe_foldr_swap (f : α → β → β) (H : left_commutative f) (b : β) (l : list α) :
id                                            └──────────────┘               └──┘ 
src                                              └──────────────┘                 └──┘
typ                                           └──────────────┘               └──┘ 
701    foldr f H b l = l.foldl (λ x y, f y x) b :=
id     └───┘      └────┘           
src    └───┘           └────┘
typ    └───┘      └────┘           
doc    └───┘
702  (congr_arg (foldr f H b) (coe_reverse l)).symm.trans $ foldr_reverse _ _ _
id    └───────┘  └───┘      └─────────┘   └──┘ └───┘    └───────────┘
src   └───────┘  └───┘         └─────────┘    └──┘ └───┘    └───────────┘
typ   └───────┘  └───┘      └─────────┘   └──┘ └───┘    └───────────┘
doc              └───┘
703  
704  theorem foldr_swap (f : α → β → β) (H : left_commutative f) (b : β) (s : multiset α) :
id                                        └──────────────┘               └──────┘ 
src                                          └──────────────┘                 └──────┘
typ                                       └──────────────┘               └──────┘ 
doc                                                                           └──────┘
705    foldr f H b s = foldl (λ x y, f y x) (λ x y z, (H _ _ _).symm) b s :=
id     └───┘      └───┘                          └──┘    
src    └───┘          └───┘                                   └──┘
typ    └───┘      └───┘                          └──┘    
doc    └───┘           └───┘
706  quot.induction_on s $ λ l, coe_foldr_swap _ _ _ _
id   └───────────────┘        └────────────┘
src  └───────────────┘          └────────────┘
typ  └───────────────┘        └────────────┘
707  
708  theorem foldl_swap (f : β → α → β) (H : right_commutative f) (b : β) (s : multiset α) :
id                                        └───────────────┘               └──────┘ 
src                                          └───────────────┘                 └──────┘
typ                                       └───────────────┘               └──────┘ 
doc                                                                            └──────┘
709    foldl f H b s = foldr (λ x y, f y x) (λ x y z, (H _ _ _).symm) b s :=
id     └───┘      └───┘                          └──┘    
src    └───┘          └───┘                                   └──┘
typ    └───┘      └───┘                          └──┘    
doc    └───┘           └───┘
710  (foldr_swap _ _ _ _).symm
id    └────────┘         └──┘
src   └────────┘         └──┘
typ   └────────┘         └──┘
711  
712  /-- Product of a multiset given a commutative monoid structure on `α`.
713    `prod {a, b, c} = a * b * c` -/
714  @[to_additive]
doc    └─────────┘
715  def prod [comm_monoid α] : multiset α → α :=
id             └─────────┘     └──────┘    
src            └─────────┘      └──────┘
typ            └─────────┘     └──────┘    
doc                             └──────┘
716  foldr (*) (λ x y z, by simp [mul_left_comm]) 1
id   └───┘                    └───────────┘
src  └───┘                 └────┘└───────────┘
typ  └───┘              └────┘└───────────┘
doc  └───┘                  └────┘             
txt                         └────┘             
par                         └────┘             
pid                                          
st                         └───────────────────┘
717  
718  @[to_additive]
doc    └─────────┘
719  theorem prod_eq_foldr [comm_monoid α] (s : multiset α) :
id                          └─────────┘        └──────┘ 
src                         └─────────┘         └──────┘
typ                         └─────────┘        └──────┘ 
doc                                             └──────┘
720    prod s = foldr (*) (λ x y z, by simp [mul_left_comm]) 1 s := rfl
id     └──┘   └───┘                    └───────────┘         └─┘
src    └──┘    └───┘                 └────┘└───────────┘         └─┘
typ    └──┘   └───┘              └────┘└───────────┘        └─┘
doc    └──┘     └───┘                  └────┘             
txt                                    └────┘             
par                                    └────┘             
pid                                                     
st                                    └───────────────────┘
721  
722  @[to_additive]
doc    └─────────┘
723  theorem prod_eq_foldl [comm_monoid α] (s : multiset α) :
id                          └─────────┘        └──────┘ 
src                         └─────────┘         └──────┘
typ                         └─────────┘        └──────┘ 
doc                                             └──────┘
724    prod s = foldl (*) (λ x y z, by simp [mul_right_comm]) 1 s :=
id     └──┘   └───┘                    └────────────┘     
src    └──┘    └───┘                 └────┘└────────────┘
typ    └──┘   └───┘              └────┘└────────────┘    
doc    └──┘     └───┘                  └────┘              
txt                                    └────┘              
par                                    └────┘              
pid                                                      
st                                    └────────────────────┘
725  (foldr_swap _ _ _ _).trans (by simp [mul_comm])
id    └────────┘         └───┘            └──────┘
src   └────────┘         └───┘      └────┘└──────┘
typ   └────────┘         └───┘      └────┘└──────┘
doc                                 └────┘        
txt                                 └────┘        
par                                 └────┘        
pid                                             
st                                 └──────────────┘
726  
727  @[simp, to_additive]
doc    └──┘  └─────────┘
728  theorem coe_prod [comm_monoid α] (l : list α) : prod ↑l = l.prod :=
id                     └─────────┘        └──┘     └──┘   └───┘
src                    └─────────┘         └──┘      └──┘     └───┘
typ                    └─────────┘        └──┘     └──┘   └───┘
doc                                                  └──┘       └───┘
729  prod_eq_foldl _
id   └───────────┘
src  └───────────┘
typ  └───────────┘
730  
731  @[simp, to_additive]
doc    └──┘  └─────────┘
732  theorem prod_zero [comm_monoid α] : @prod α _ 0 = 1 := rfl
id                      └─────────┘      └──┘            └─┘
src                     └─────────┘       └──┘             └─┘
typ                     └─────────┘      └──┘            └─┘
doc                                       └──┘
733  
734  @[simp, to_additive]
doc    └──┘  └─────────┘
735  theorem prod_cons [comm_monoid α] (a : α) (s) : prod (a :: s) = a * prod s :=
id                      └─────────┘                └──┘   └┘      └──┘ 
src                     └─────────┘                  └──┘    └┘        └──┘
typ                     └─────────┘                └──┘   └┘      └──┘ 
doc                                                  └──┘    └┘          └──┘
736  foldr_cons _ _ _ _ _
id   └────────┘
src  └────────┘
typ  └────────┘
737  
738  @[to_additive]
doc    └─────────┘
739  theorem prod_singleton [comm_monoid α] (a : α) : prod (a :: 0) = a := by simp
id                           └─────────┘            └──┘   └┘     
src                          └─────────┘              └──┘    └┘             └────
typ                          └─────────┘            └──┘   └┘            └────
doc                                                   └──┘    └┘              └────
txt                                                                           └────
par                                                                           └────
pid                                                                               
st                                                                           └─────
740  
src  
typ  
doc  
txt  
par  
pid  
st   
741  @[simp, to_additive]
doc    └──┘  └─────────┘
742  theorem prod_add [comm_monoid α] (s t : multiset α) : prod (s + t) = prod s * prod t :=
id                     └─────────┘          └──────┘     └──┘       └──┘   └──┘ 
src                    └─────────┘           └──────┘      └──┘         └──┘    └──┘
typ                    └─────────┘          └──────┘     └──┘       └──┘   └──┘ 
doc                                          └──────┘      └──┘           └──┘     └──┘
743  quotient.induction_on₂ s t $ λ l₁ l₂, by simp
id   └────────────────────┘       └┘ └┘
src  └────────────────────┘                   └────
typ  └────────────────────┘       └┘ └┘     └────
doc                                           └────
txt                                           └────
par                                           └────
pid                                               
st                                           └─────
744  
src  
typ  
doc  
txt  
par  
pid  
st   
745  instance sum.is_add_monoid_hom [add_comm_monoid α] : is_add_monoid_hom (sum : multiset α → α) :=
id                                   └─────────────┘     └───────────────┘  └─┘   └──────┘    
src                                  └─────────────┘      └───────────────┘  └─┘   └──────┘
typ                                  └─────────────┘     └───────────────┘  └─┘   └──────┘    
doc                                                       └───────────────┘        └──────┘
746  { map_add := sum_add, map_zero := sum_zero }
id                └─────┘              └──────┘
src               └─────┘              └──────┘
typ               └─────┘              └──────┘
747  
748  lemma prod_smul {α : Type*} [comm_monoid α] (m : multiset α) :
id                                └─────────┘        └──────┘ 
src                               └─────────┘         └──────┘
typ                               └─────────┘        └──────┘ 
doc                                                   └──────┘
749    ∀n, (add_monoid.smul n m).prod = m.prod ^ n
id         └─────────────┘   └──┘   └───┘  
src         └─────────────┘     └──┘    └───┘ 
typ        └─────────────┘   └──┘   └───┘  
doc                             └──┘     └───┘
750  | 0       := rfl
id                └─┘
src               └─┘
typ               └─┘
751  | (n + 1) :=
id        
src       
typ       
752    by rw [add_monoid.add_smul, add_monoid.one_smul, _root_.pow_add, _root_.pow_one, prod_add, prod_smul n]
id            └─────────────────┘  └─────────────────┘  └────────────┘  └────────────┘  └──────┘  └───────┘ 
src       └──┘└─────────────────┘└┘└─────────────────┘└┘└────────────┘└┘└────────────┘└┘└──────┘└┘          └─
typ       └──┘└─────────────────┘└┘└─────────────────┘└┘└────────────┘└┘└────────────┘└┘└──────┘└┘└───────┘└─
doc       └──┘                   └┘                   └┘              └┘              └┘        └┘          └─
txt       └──┘                   └┘                   └┘              └┘              └┘        └┘          └─
par       └──┘                   └┘                   └┘              └┘              └┘        └┘          └─
pid         └┘                   └┘                   └┘              └┘              └┘        └┘          
st       └──────────────────────┘└───────────────────┘└──────────────┘└──────────────┘└────────┘└───────────┘
753  
src  
typ  
doc  
txt  
par  
pid  
st   
754  @[simp] theorem prod_repeat [comm_monoid α] (a : α) (n : ℕ) : prod (multiset.repeat a n) = a ^ n :=
id                                └─────────┘                   └──┘  └─────────────┘       
src                               └─────────┘                     └──┘  └─────────────┘         
typ                               └─────────┘                   └──┘  └─────────────┘       
doc    └──┘                                                        └──┘  └─────────────┘
755  by simp [repeat, list.prod_repeat]
id            └────┘  └──────────────┘
src     └────┘└────┘└┘└──────────────┘└┘
typ     └────┘└────┘└┘└──────────────┘└┘
doc     └────┘└────┘└┘                └┘
txt     └────┘      └┘                └┘
par     └────┘      └┘                └┘
pid               └┘                
st     └───────────────────────────────┘
756  @[simp] theorem sum_repeat [add_comm_monoid α] : ∀ (a : α) (n : ℕ), sum (multiset.repeat a n) = n • a :=
id                               └─────────────┘                      └─┘  └─────────────┘       
src                              └─────────────┘                        └─┘  └─────────────┘         
typ                              └─────────────┘                      └─┘  └─────────────┘       
doc    └──┘                                                                   └─────────────┘
757  @prod_repeat (multiplicative α) _
id    └─────────┘  └────────────┘ 
src   └─────────┘  └────────────┘
typ   └─────────┘  └────────────┘ 
758  attribute [to_additive] prod_repeat
id                           └─────────┘
src                          └─────────┘
typ                          └─────────┘
doc             └─────────┘
759  
760  @[simp] lemma prod_map_one [comm_monoid γ] {m : multiset α} :
id                               └─────────┘        └──────┘ 
src                              └─────────┘         └──────┘
typ                              └─────────┘        └──────┘ 
doc    └──┘                                          └──────┘
761    prod (m.map (λa, (1 : γ))) = (1 : γ) :=
id     └──┘  └──┘                    
src    └──┘   └──┘                
typ    └──┘  └──┘                    
doc    └──┘   └──┘
762  multiset.induction_on m (by simp) (by simp)
id   └───────────────────┘ 
src  └───────────────────┘       └──┘      └──┘
typ  └───────────────────┘      └──┘      └──┘
doc                              └──┘      └──┘
txt                              └──┘      └──┘
par                              └──┘      └──┘
st                              └───┘     └───┘
763  @[simp] lemma sum_map_zero [add_comm_monoid γ] {m : multiset α} :
id                               └─────────────┘        └──────┘ 
src                              └─────────────┘         └──────┘
typ                              └─────────────┘        └──────┘ 
doc    └──┘                                              └──────┘
764    sum (m.map (λa, (0 : γ))) = (0 : γ) :=
id     └─┘  └──┘                    
src    └─┘   └──┘                
typ    └─┘  └──┘                    
doc          └──┘
765  multiset.induction_on m (by simp) (by simp)
id   └───────────────────┘ 
src  └───────────────────┘       └──┘      └──┘
typ  └───────────────────┘      └──┘      └──┘
doc                              └──┘      └──┘
txt                              └──┘      └──┘
par                              └──┘      └──┘
st                              └───┘     └───┘
766  attribute [to_additive] prod_map_one
id                           └──────────┘
src                          └──────────┘
typ                          └──────────┘
doc             └─────────┘
767  
768  @[simp, to_additive]
doc    └──┘  └─────────┘
769  lemma prod_map_mul [comm_monoid γ] {m : multiset α} {f g : α → γ} :
id                       └─────────┘        └──────┘             
src                      └─────────┘         └──────┘
typ                      └─────────┘        └──────┘             
doc                                          └──────┘
770    prod (m.map $ λa, f a * g a) = prod (m.map f) * prod (m.map g) :=
id     └──┘  └──┘             └──┘  └──┘    └──┘  └──┘ 
src    └──┘   └──┘                  └──┘   └──┘     └──┘   └──┘
typ    └──┘  └──┘             └──┘  └──┘    └──┘  └──┘ 
doc    └──┘   └──┘                    └──┘   └──┘      └──┘   └──┘
771  multiset.induction_on m (by simp) (assume a m ih, by simp [ih]; cc)
id   └───────────────────┘                      └┘           └┘
src  └───────────────────┘       └──┘                     └────┘    └┘
typ  └───────────────────┘      └──┘            └┘     └────┘└┘  └┘
doc                              └──┘                     └────┘    └┘
txt                              └──┘                     └────┘    └┘
par                              └──┘                     └────┘    └┘
pid                                                             
st                              └───┘                    └────────────┘
772  
773  lemma prod_map_prod_map [comm_monoid γ] (m : multiset α) (n : multiset β) {f : α → β → γ} :
id                            └─────────┘        └──────┘        └──────┘              
src                           └─────────┘         └──────┘         └──────┘
typ                           └─────────┘        └──────┘        └──────┘              
doc                                               └──────┘         └──────┘
774    prod (m.map $ λa, prod $ n.map $ λb, f a b) = prod (n.map $ λb, prod $ m.map $ λa, f a b) :=
id     └──┘  └──┘      └──┘   └──┘           └──┘  └──┘      └──┘   └──┘        
src    └──┘   └──┘       └──┘    └──┘               └──┘   └──┘       └──┘    └──┘
typ    └──┘  └──┘      └──┘   └──┘           └──┘  └──┘      └──┘   └──┘        
doc    └──┘   └──┘       └──┘    └──┘                └──┘   └──┘       └──┘    └──┘
775  multiset.induction_on m (by simp) (assume a m ih, by simp [ih])
id   └───────────────────┘                      └┘           └┘
src  └───────────────────┘       └──┘                     └────┘  
typ  └───────────────────┘      └──┘            └┘     └────┘└┘
doc                              └──┘                     └────┘  
txt                              └──┘                     └────┘  
par                              └──┘                     └────┘  
pid                                                             
st                              └───┘                    └────────┘
776  
777  lemma sum_map_sum_map [add_comm_monoid γ] : ∀ (m : multiset α) (n : multiset β) {f : α → β → γ},
id                          └─────────────┘            └──────┘        └──────┘             
src                         └─────────────┘             └──────┘         └──────┘
typ                         └─────────────┘            └──────┘        └──────┘             
doc                                                     └──────┘         └──────┘
778    sum (m.map $ λa, sum $ n.map $ λb, f a b) = sum (n.map $ λb, sum $ m.map $ λa, f a b) :=
id     └─┘  └──┘      └─┘   └──┘           └─┘  └──┘      └─┘   └──┘        
src    └─┘   └──┘       └─┘    └──┘               └─┘   └──┘       └─┘    └──┘
typ    └─┘  └──┘      └─┘   └──┘           └─┘  └──┘      └─┘   └──┘        
doc          └──┘              └──┘                      └──┘              └──┘
779  @prod_map_prod_map _ _ (multiplicative γ) _
id    └───────────────┘      └────────────┘ 
src   └───────────────┘      └────────────┘
typ   └───────────────┘      └────────────┘ 
780  attribute [to_additive] prod_map_prod_map
id                           └───────────────┘
src                          └───────────────┘
typ                          └───────────────┘
doc             └─────────┘
781  
782  lemma sum_map_mul_left [semiring β] {b : β} {s : multiset α} {f : α → β} :
id                           └──────┘               └──────┘           
src                          └──────┘                 └──────┘
typ                          └──────┘               └──────┘           
doc                                                   └──────┘
783    sum (s.map (λa, b * f a)) = b * sum (s.map f) :=
id     └─┘  └──┘              └─┘  └──┘ 
src    └─┘   └──┘                   └─┘   └──┘
typ    └─┘  └──┘              └─┘  └──┘ 
doc          └──┘                            └──┘
784  multiset.induction_on s (by simp) (assume a s ih, by simp [ih, mul_add])
id   └───────────────────┘                      └┘           └┘  └─────┘
src  └───────────────────┘       └──┘                     └────┘  └┘└─────┘
typ  └───────────────────┘      └──┘            └┘     └────┘└┘└┘└─────┘
doc                              └──┘                     └────┘  └┘       
txt                              └──┘                     └────┘  └┘       
par                              └──┘                     └────┘  └┘       
pid                                                             └┘       
st                              └───┘                    └─────────────────┘
785  
786  lemma sum_map_mul_right [semiring β] {b : β} {s : multiset α} {f : α → β} :
id                            └──────┘               └──────┘           
src                           └──────┘                 └──────┘
typ                           └──────┘               └──────┘           
doc                                                    └──────┘
787    sum (s.map (λa, f a * b)) = sum (s.map f) * b :=
id     └─┘  └──┘            └─┘  └──┘    
src    └─┘   └──┘                └─┘   └──┘    
typ    └─┘  └──┘            └─┘  └──┘    
doc          └──┘                        └──┘
788  multiset.induction_on s (by simp) (assume a s ih, by simp [ih, add_mul])
id   └───────────────────┘                      └┘           └┘  └─────┘
src  └───────────────────┘       └──┘                     └────┘  └┘└─────┘
typ  └───────────────────┘      └──┘            └┘     └────┘└┘└┘└─────┘
doc                              └──┘                     └────┘  └┘       
txt                              └──┘                     └────┘  └┘       
par                              └──┘                     └────┘  └┘       
pid                                                             └┘       
st                              └───┘                    └─────────────────┘
789  
790  @[to_additive]
doc    └─────────┘
791  lemma prod_hom [comm_monoid α] [comm_monoid β] (s : multiset α) (f : α → β) [is_monoid_hom f] :
id                   └─────────┘    └─────────┘        └──────┘              └───────────┘ 
src                  └─────────┘     └─────────┘         └──────┘                 └───────────┘
typ                  └─────────┘    └─────────┘        └──────┘              └───────────┘ 
doc                                                      └──────┘                 └───────────┘
792    (s.map f).prod = f s.prod :=
id      └──┘  └──┘    └───┘
src      └──┘   └──┘      └───┘
typ     └──┘  └──┘    └───┘
doc      └──┘   └──┘       └───┘
793  quotient.induction_on s $ λ l, by simp only [l.prod_hom f, quot_mk_to_coe, coe_map, coe_prod]
id   └───────────────────┘                      └────────┘   └────────────┘  └─────┘  └──────┘
src  └───────────────────┘             └─────────┘└────────┘ └┘└────────────┘└┘└─────┘└┘└──────┘└─
typ  └───────────────────┘           └─────────┘└────────┘└┘└────────────┘└┘└─────┘└┘└──────┘└─
doc                                    └─────────┘           └┘              └┘       └┘        └─
txt                                    └─────────┘           └┘              └┘       └┘        └─
par                                    └─────────┘           └┘              └┘       └┘        └─
pid                                        └──┘└┘           └┘              └┘       └┘        
st                                    └────────────────────────────────────────────────────────────
794  
src  
typ  
doc  
txt  
par  
pid  
st   
795  @[to_additive]
doc    └─────────┘
796  theorem prod_hom_rel [comm_monoid β] [comm_monoid γ] (s : multiset α) {r : β → γ → Prop}
id                         └─────────┘    └─────────┘        └──────┘           
src                        └─────────┘     └─────────┘         └──────┘
typ                        └─────────┘    └─────────┘        └──────┘           
doc                                                            └──────┘
797    {f : α → β} {g : α → γ} (h₁ : r 1 1) (h₂ : ∀⦃a b c⦄, r b c → r (f a * b) (g a * c)) :
id                                                                  
src                                                                                 
typ                                                                 
798    r (s.map f).prod (s.map g).prod :=
id       └──┘  └──┘   └──┘  └──┘
src        └──┘   └──┘    └──┘   └──┘
typ      └──┘  └──┘   └──┘  └──┘
doc        └──┘   └──┘    └──┘   └──┘
799  quotient.induction_on s $ λ l,
id   └───────────────────┘      
src  └───────────────────┘
typ  └───────────────────┘      
800    by simp only [l.prod_hom_rel h₁ h₂, quot_mk_to_coe, coe_map, coe_prod]
id                   └────────────┘ └┘ └┘  └────────────┘  └─────┘  └──────┘
src       └─────────┘└────────────┘    └┘└────────────┘└┘└─────┘└┘└──────┘└─
typ       └─────────┘└────────────┘└┘└┘└┘└────────────┘└┘└─────┘└┘└──────┘└─
doc       └─────────┘                  └┘              └┘       └┘        └─
txt       └─────────┘                  └┘              └┘       └┘        └─
par       └─────────┘                  └┘              └┘       └┘        └─
pid           └──┘└┘                  └┘              └┘       └┘        
st       └────────────────────────────────────────────────────────────────────
801  
src  
typ  
doc  
txt  
par  
pid  
st   
802  lemma dvd_prod [comm_semiring α] {a : α} {s : multiset α} : a ∈ s → a ∣ s.prod :=
id                   └───────────┘               └──────┘            └───┘
src                  └───────────┘                 └──────┘                 └───┘
typ                  └───────────┘               └──────┘            └───┘
doc                                                └──────┘                   └───┘
803  quotient.induction_on s (λ l a h, by simpa using list.dvd_prod h) a
id   └───────────────────┘                        └───────────┘   
src  └───────────────────┘                └──────────┘└───────────┘
typ  └───────────────────┘            └──────────┘└───────────┘  
doc                                       └──────────┘             
txt                                       └──────────┘             
par                                       └──────────┘             
pid                                            └────┘             
st                                       └──────────────────────────┘
804  
805  lemma le_sum_of_subadditive [add_comm_monoid α] [ordered_comm_monoid β]
id                                └─────────────┘    └─────────────────┘ 
src                               └─────────────┘     └─────────────────┘
typ                               └─────────────┘    └─────────────────┘ 
doc                                                   └─────────────────┘
806    (f : α → β) (h_zero : f 0 = 0) (h_add : ∀x y, f (x + y) ≤ f x + f y) (s : multiset α) :
id                                                               └──────┘ 
src                                                                          └──────┘
typ                                                              └──────┘ 
doc                                                                              └──────┘
807    f s.sum ≤ (s.map f).sum :=
id      └──┘   └──┘  └─┘
src       └──┘    └──┘   └─┘
typ     └──┘   └──┘  └─┘
doc                └──┘
808  multiset.induction_on s (le_of_eq h_zero) $
id   └───────────────────┘   └──────┘ └────┘
src  └───────────────────┘    └──────┘
typ  └───────────────────┘   └──────┘ └────┘
809    assume a s ih, by rw [sum_cons, map_cons, sum_cons];
id              └┘         └──────┘  └──────┘  └──────┘
src                      └──┘└──────┘└┘└──────┘└┘└──────┘
typ             └┘     └──┘└──────┘└┘└──────┘└┘└──────┘
doc                      └──┘        └┘        └┘        
txt                      └──┘        └┘        └┘        
par                      └──┘        └┘        └┘        
pid                        └┘        └┘        └┘        
st                      └───────────┘└────────┘└────────┘└─
810      from le_trans (h_add a s.sum) (add_le_add_left' ih)
id            └──────┘  └───┘  └───┘   └──────────────┘ └┘
src      └───┘└──────┘       └───┘└┘ └──────────────┘  └─
typ      └───┘└──────┘ └───┘└───┘└┘ └──────────────┘└┘└─
doc      └───┘                    └┘                   └─
txt      └───┘                    └┘                   └─
par      └───┘                    └┘                   └─
pid      └───┘                    └┘                   
st   ────────────────────────────────────────────────────────
811  
src  
typ  
doc  
txt  
par  
pid  
st   
812  lemma abs_sum_le_sum_abs [discrete_linear_ordered_field α] {s : multiset α} :
id                             └───────────────────────────┘        └──────┘ 
src                            └───────────────────────────┘         └──────┘
typ                            └───────────────────────────┘        └──────┘ 
doc                                                                  └──────┘
813    abs s.sum ≤ (s.map abs).sum :=
id     └─┘ └──┘   └──┘ └─┘ └─┘
src    └─┘  └──┘    └──┘ └─┘ └─┘
typ    └─┘ └──┘   └──┘ └─┘ └─┘
doc                  └──┘
814  le_sum_of_subadditive _ abs_zero abs_add s
id   └───────────────────┘   └──────┘ └─────┘ 
src  └───────────────────┘   └──────┘ └─────┘
typ  └───────────────────┘   └──────┘ └─────┘ 
815  
816  theorem dvd_sum [comm_semiring α] {a : α} {s : multiset α} : (∀ x ∈ s, a ∣ x) → a ∣ s.sum :=
id                    └───────────┘               └──────┘                     └──┘
src                   └───────────┘                 └──────┘                            └──┘
typ                   └───────────┘               └──────┘                     └──┘
doc                                                 └──────┘
817  multiset.induction_on s (λ _, dvd_zero _)
id   └───────────────────┘       └──────┘
src  └───────────────────┘         └──────┘
typ  └───────────────────┘       └──────┘
818    (λ x s ih h, by rw sum_cons; exact dvd_add
id          └┘         └──────┘        └─────┘
src                    └─┘└──────┘  └────┘└─────┘
typ         └┘      └─┘└──────┘  └────┘└─────┘
doc                    └─┘          └────┘       
txt                    └─┘          └────┘       
par                    └─┘          └────┘       
pid                                            
st                    └───────────────────────────
819      (h _ (mem_cons_self _ _)) (ih (λ y hy, h _ (mem_cons.2 (or.inr hy)))))
id             └───────────┘        └┘              └──────┘    └────┘
src  ───┘  └─┘ └───────────┘└─────┘     └─────┘ └─┘ └──────┘└─┘ └────┘  └──┘
typ  ───┘  └─┘ └───────────┘└─────┘ └┘  └─────┘└─┘ └──────┘└─┘ └────┘  └──┘
doc  ───┘  └─┘              └─────┘     └─────┘ └─┘         └─┘         └──┘
txt  ───┘  └─┘              └─────┘     └─────┘ └─┘         └─┘         └──┘
par  ───┘  └─┘              └─────┘     └─────┘ └─┘         └─┘         └──┘
pid  ───┘  └─┘              └─────┘     └─────┘ └─┘         └─┘         └──┘
st   ────────────────────────────────────────────────────────────────────────┘
820  
821  /- join -/
822  
823  /-- `join S`, where `S` is a multiset of multisets, is the lift of the list join
824    operation, that is, the union of all the sets.
825  
826       join {{1, 2}, {1, 2}, {0, 1}} = {0, 1, 1, 1, 2, 2} -/
827  def join : multiset (multiset α) → multiset α := sum
id              └──────┘  └──────┘     └──────┘     └─┘
src             └──────┘  └──────┘      └──────┘      └─┘
typ             └──────┘  └──────┘     └──────┘     └─┘
doc             └──────┘  └──────┘      └──────┘
828  
829  theorem coe_join : ∀ L : list (list α),
id                           └──┘  └──┘ 
src                           └──┘  └──┘
typ                          └──┘  └──┘ 
830    join (L.map (@coe _ (multiset α) _) : multiset (multiset α)) = L.join
id     └──┘  └──┘   └─┘    └──────┘        └──────┘  └──────┘     └───┘
src    └──┘   └──┘   └─┘    └──────┘         └──────┘  └──────┘       └───┘
typ    └──┘  └──┘   └─┘    └──────┘        └──────┘  └──────┘     └───┘
doc    └──┘                 └──────┘         └──────┘  └──────┘
831  | []       := rfl
id     └┘          └─┘
src    └┘          └─┘
typ    └┘          └─┘
832  | (l :: L) := congr_arg (λ s : multiset α, ↑l + s) (coe_join L)
id       └┘      └───────┘        └──────┘         └──────┘
src       └┘       └───────┘        └──────┘      
typ      └┘      └───────┘        └──────┘         └──────┘
doc                                 └──────┘
833  
834  @[simp] theorem join_zero : @join α 0 = 0 := rfl
id                                └──┘          └─┘
src                               └──┘           └─┘
typ                               └──┘          └─┘
doc    └──┘                       └──┘
835  
836  @[simp] theorem join_cons (s S) : @join α (s :: S) = s + join S :=
id                                      └──┘    └┘      └──┘ 
src                                     └──┘      └┘        └──┘
typ                                     └──┘    └┘      └──┘ 
doc    └──┘                             └──┘      └┘          └──┘
837  sum_cons _ _
id   └──────┘
src  └──────┘
typ  └──────┘
838  
839  @[simp] theorem join_add (S T) : @join α (S + T) = join S + join T :=
id                                     └──┘        └──┘   └──┘ 
src                                    └──┘           └──┘    └──┘
typ                                    └──┘        └──┘   └──┘ 
doc    └──┘                            └──┘             └──┘     └──┘
840  sum_add _ _
id   └─────┘
src  └─────┘
typ  └─────┘
841  
842  @[simp] theorem mem_join {a S} : a ∈ @join α S ↔ ∃ s ∈ S, a ∈ s :=
id                                       └──┘           
src                                       └──┘               
typ                                      └──┘           
doc    └──┘                                └──┘
843  multiset.induction_on S (by simp) $
id   └───────────────────┘ 
src  └───────────────────┘       └──┘
typ  └───────────────────┘      └──┘
doc                              └──┘
txt                              └──┘
par                              └──┘
st                              └───┘
844    by simp [or_and_distrib_right, exists_or_distrib] {contextual := tt}
id              └──────────────────┘  └───────────────┘                 └┘
src       └────┘└──────────────────┘└┘└───────────────┘└┘ └────────────┘└┘└─
typ       └────┘└──────────────────┘└┘└───────────────┘└┘ └────────────┘└┘└─
doc       └────┘                    └┘                 └┘ └────────────┘  └─
txt       └────┘                    └┘                 └┘ └────────────┘  └─
par       └────┘                    └┘                 └┘ └────────────┘  └─
pid                               └┘                  └────────────┘  
st       └──────────────────────────────────────────────────────────────────
845  
src  
typ  
doc  
txt  
par  
pid  
st   
846  @[simp] theorem card_join (S) : card (@join α S) = sum (map card S) :=
id                                   └──┘   └──┘     └─┘  └─┘ └──┘ 
src                                  └──┘   └──┘       └─┘  └─┘ └──┘
typ                                  └──┘   └──┘     └─┘  └─┘ └──┘ 
doc    └──┘                          └──┘   └──┘             └─┘ └──┘
847  multiset.induction_on S (by simp) (by simp)
id   └───────────────────┘ 
src  └───────────────────┘       └──┘      └──┘
typ  └───────────────────┘      └──┘      └──┘
doc                              └──┘      └──┘
txt                              └──┘      └──┘
par                              └──┘      └──┘
st                              └───┘     └───┘
848  
849  /- bind -/
850  
851  /-- `bind s f` is the monad bind operation, defined as `join (map f s)`.
852    It is the union of `f a` as `a` ranges over `s`. -/
853  def bind (s : multiset α) (f : α → multiset β) : multiset β :=
id                 └──────┘           └──────┘     └──────┘ 
src                └──────┘             └──────┘      └──────┘
typ                └──────┘           └──────┘     └──────┘ 
doc                └──────┘             └──────┘      └──────┘
854  join (map f s)
id   └──┘  └─┘  
src  └──┘  └─┘
typ  └──┘  └─┘  
doc  └──┘  └─┘
855  
856  @[simp] theorem coe_bind (l : list α) (f : α → list β) :
id                                 └──┘           └──┘ 
src                                └──┘             └──┘
typ                                └──┘           └──┘ 
doc    └──┘
857    @bind α β l (λ a, f a) = l.bind f :=
id      └──┘             └───┘ 
src     └──┘                    └───┘
typ     └──┘             └───┘ 
doc     └──┘
858  by rw [list.bind, ← coe_join, list.map_map]; refl
id          └───────┘    └──────┘  └──────────┘
src     └──┘└───────┘└──┘└──────┘└┘└──────────┘  └────
typ     └──┘└───────┘└──┘└──────┘└┘└──────────┘  └────
doc     └──┘         └──┘        └┘              └────
txt     └──┘         └──┘        └┘              └────
par     └──┘         └──┘        └┘              └────
pid       └┘         └──┘        └┘                  
st     └────────────┘└──────────┘└────────────┘└──────
859  
src  
typ  
doc  
txt  
par  
pid  
st   
860  @[simp] theorem zero_bind (f : α → multiset β) : bind 0 f = 0 := rfl
id                                     └──────┘     └──┘          └─┘
src                                     └──────┘      └──┘           └─┘
typ                                    └──────┘     └──┘          └─┘
doc    └──┘                             └──────┘      └──┘
861  
862  @[simp] theorem cons_bind (a s) (f : α → multiset β) : bind (a::s) f = f a + bind s f :=
id                                           └──────┘     └──┘  └┘       └──┘  
src                                           └──────┘      └──┘   └┘           └──┘
typ                                          └──────┘     └──┘  └┘       └──┘  
doc    └──┘                                   └──────┘      └──┘   └┘             └──┘
863  by simp [bind]
id            └──┘
src     └────┘└──┘└─
typ     └────┘└──┘└─
doc     └────┘└──┘└─
txt     └────┘    └─
par     └────┘    └─
pid             
st     └────────────
864  
src  
typ  
doc  
txt  
par  
pid  
st   
865  @[simp] theorem add_bind (s t) (f : α → multiset β) : bind (s + t) f = bind s f + bind t f :=
id                                          └──────┘     └──┘        └──┘    └──┘  
src                                          └──────┘      └──┘           └──┘      └──┘
typ                                         └──────┘     └──┘        └──┘    └──┘  
doc    └──┘                                  └──────┘      └──┘             └──┘       └──┘
866  by simp [bind]
id            └──┘
src     └────┘└──┘└─
typ     └────┘└──┘└─
doc     └────┘└──┘└─
txt     └────┘    └─
par     └────┘    └─
pid             
st     └────────────
867  
src  
typ  
doc  
txt  
par  
pid  
st   
868  @[simp] theorem bind_zero (s : multiset α) : bind s (λa, 0 : α → multiset β) = 0 :=
id                                  └──────┘     └──┘             └──────┘   
src                                 └──────┘      └──┘                └──────┘    
typ                                 └──────┘     └──┘             └──────┘   
doc    └──┘                         └──────┘      └──┘                └──────┘
869  by simp [bind, -map_const, join]
id            └──┘              └──┘
src     └────┘└──┘└────────────┘└──┘└─
typ     └────┘└──┘└────────────┘└──┘└─
doc     └────┘└──┘└────────────┘└──┘└─
txt     └────┘    └────────────┘    └─
par     └────┘    └────────────┘    └─
pid             └────────────┘    
st     └──────────────────────────────
870  
src  
typ  
doc  
txt  
par  
pid  
st   
871  @[simp] theorem bind_add (s : multiset α) (f g : α → multiset β) :
id                                 └──────┘             └──────┘ 
src                                └──────┘               └──────┘
typ                                └──────┘             └──────┘ 
doc    └──┘                        └──────┘               └──────┘
872    bind s (λa, f a + g a) = bind s f + bind s g :=
id     └──┘             └──┘    └──┘  
src    └──┘                   └──┘      └──┘
typ    └──┘             └──┘    └──┘  
doc    └──┘                     └──┘       └──┘
873  by simp [bind, join]
id            └──┘  └──┘
src     └────┘└──┘└┘└──┘└─
typ     └────┘└──┘└┘└──┘└─
doc     └────┘└──┘└┘└──┘└─
txt     └────┘    └┘    └─
par     └────┘    └┘    └─
pid             └┘    
st     └──────────────────
874  
src  
typ  
doc  
txt  
par  
pid  
st   
875  @[simp] theorem bind_cons (s : multiset α) (f : α → β) (g : α → multiset β) :
id                                  └──────┘                     └──────┘ 
src                                 └──────┘                         └──────┘
typ                                 └──────┘                     └──────┘ 
doc    └──┘                         └──────┘                         └──────┘
876    bind s (λa, f a :: g a) = map f s + bind s g :=
id     └──┘        └┘     └─┘    └──┘  
src    └──┘            └┘       └─┘      └──┘
typ    └──┘        └┘     └─┘    └──┘  
doc    └──┘            └┘        └─┘       └──┘
877  multiset.induction_on s (by simp) (by simp {contextual := tt})
id   └───────────────────┘                                    └┘
src  └───────────────────┘       └──┘      └───┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └───┘ └────────────┘└┘
doc                              └──┘      └───┘ └────────────┘  
txt                              └──┘      └───┘ └────────────┘  
par                              └──┘      └───┘ └────────────┘  
pid                                             └────────────┘  
st                              └───┘     └──────────────────────┘
878  
879  @[simp] theorem mem_bind {b s} {f : α → multiset β} : b ∈ bind s f ↔ ∃ a ∈ s, b ∈ f a :=
id                                          └──────┘       └──┘            
src                                          └──────┘         └──┘               
typ                                         └──────┘       └──┘            
doc    └──┘                                  └──────┘          └──┘
880  by simp [bind]; simp [-exists_and_distrib_right, exists_and_distrib_right.symm];
id            └──┘
src     └────┘└──┘  └───────────────────────────────┘                             
typ     └────┘└──┘  └───────────────────────────────┘└───────────────────────────┘
doc     └────┘└──┘  └───────────────────────────────┘                             
txt     └────┘      └───────────────────────────────┘                             
par     └────┘      └───────────────────────────────┘                             
pid                   └──────────────────────────┘                             
st     └──────────────────────────────────────────────────────────────────────────────
881     rw exists_swap; simp [and_assoc]
id         └─────────┘        └───────┘
src     └─┘└─────────┘  └────┘└───────┘└─
typ     └─┘└─────────┘  └────┘└───────┘└─
doc     └─┘             └────┘         └─
txt     └─┘             └────┘         └─
par     └─┘             └────┘         └─
pid                                 
st   ─────┘└─────────┘└──────────────────
882  
src  
typ  
doc  
txt  
par  
pid  
st   
883  @[simp] theorem card_bind (s) (f : α → multiset β) : card (bind s f) = sum (map (card ∘ f) s) :=
id                                         └──────┘     └──┘  └──┘     └─┘  └─┘  └──┘    
src                                         └──────┘      └──┘  └──┘       └─┘  └─┘  └──┘ 
typ                                        └──────┘     └──┘  └──┘     └─┘  └─┘  └──┘    
doc    └──┘                                 └──────┘      └──┘  └──┘             └─┘  └──┘
884  by simp [bind]
id            └──┘
src     └────┘└──┘└─
typ     └────┘└──┘└─
doc     └────┘└──┘└─
txt     └────┘    └─
par     └────┘    └─
pid             
st     └────────────
885  
src  
typ  
doc  
txt  
par  
pid  
st   
886  lemma bind_congr {f g : α → multiset β} {m : multiset α} : (∀a∈m, f a = g a) → bind m f = bind m g :=
id                              └──────┘        └──────┘                  └──┘    └──┘  
src                              └──────┘         └──────┘                         └──┘      └──┘
typ                             └──────┘        └──────┘                  └──┘    └──┘  
doc                              └──────┘         └──────┘                          └──┘       └──┘
887  by simp [bind] {contextual := tt}
id            └──┘                 └┘
src     └────┘└──┘└┘ └────────────┘└┘└─
typ     └────┘└──┘└┘ └────────────┘└┘└─
doc     └────┘└──┘└┘ └────────────┘  └─
txt     └────┘    └┘ └────────────┘  └─
par     └────┘    └┘ └────────────┘  └─
pid              └────────────┘  
st     └───────────────────────────────
888  
src  
typ  
doc  
txt  
par  
pid  
st   
889  lemma bind_hcongr {β' : Type*} {m : multiset α} {f : α → multiset β} {f' : α → multiset β'}
id                                       └──────┘           └──────┘            └──────┘ └┘
src                                      └──────┘             └──────┘              └──────┘
typ                                      └──────┘           └──────┘            └──────┘ └┘
doc                                      └──────┘             └──────┘              └──────┘
890    (h : β = β') (hf : ∀a∈m, f a == f' a) : bind m f == bind m f' :=
id            └┘              └┘ └┘     └──┘   └┘ └──┘  └┘
src                                └┘         └──┘     └┘ └──┘
typ           └┘              └┘ └┘     └──┘   └┘ └──┘  └┘
doc                                            └──┘        └──┘
891  begin subst h, simp at hf, simp [bind_congr hf] end
id                                   └────────┘ └┘
src        └────┘   └────────┘  └────┘└────────┘  └┘
typ        └────┘  └────────┘  └────┘└────────┘└┘└┘
doc        └────┘   └────────┘  └────┘            └┘
txt        └────┘   └────────┘  └────┘            └┘
par        └────┘   └────────┘  └────┘            └┘
pid                    └───┘                  
st   └───────────┘└──────────┘└─────────────────────┘└─┘
892  
893  lemma map_bind (m : multiset α) (n : α → multiset β) (f : β → γ) :
id                       └──────┘           └──────┘           
src                      └──────┘             └──────┘
typ                      └──────┘           └──────┘           
doc                      └──────┘             └──────┘
894    map f (bind m n) = bind m (λa, map f (n a)) :=
id     └─┘   └──┘     └──┘      └─┘    
src    └─┘    └──┘       └──┘        └─┘
typ    └─┘   └──┘     └──┘      └─┘    
doc    └─┘    └──┘        └──┘        └─┘
895  multiset.induction_on m (by simp) (by simp {contextual := tt})
id   └───────────────────┘                                    └┘
src  └───────────────────┘       └──┘      └───┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └───┘ └────────────┘└┘
doc                              └──┘      └───┘ └────────────┘  
txt                              └──┘      └───┘ └────────────┘  
par                              └──┘      └───┘ └────────────┘  
pid                                             └────────────┘  
st                              └───┘     └──────────────────────┘
896  
897  lemma bind_map (m : multiset α) (n : β → multiset γ) (f : α → β) :
id                       └──────┘           └──────┘           
src                      └──────┘             └──────┘
typ                      └──────┘           └──────┘           
doc                      └──────┘             └──────┘
898    bind (map f m) n = bind m (λa, n (f a)) :=
id     └──┘  └─┘      └──┘         
src    └──┘  └─┘         └──┘
typ    └──┘  └─┘      └──┘         
doc    └──┘  └─┘          └──┘
899  multiset.induction_on m (by simp) (by simp {contextual := tt})
id   └───────────────────┘                                    └┘
src  └───────────────────┘       └──┘      └───┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └───┘ └────────────┘└┘
doc                              └──┘      └───┘ └────────────┘  
txt                              └──┘      └───┘ └────────────┘  
par                              └──┘      └───┘ └────────────┘  
pid                                             └────────────┘  
st                              └───┘     └──────────────────────┘
900  
901  lemma bind_assoc {s : multiset α} {f : α → multiset β} {g : β → multiset γ} :
id                         └──────┘           └──────┘           └──────┘ 
src                        └──────┘             └──────┘             └──────┘
typ                        └──────┘           └──────┘           └──────┘ 
doc                        └──────┘             └──────┘             └──────┘
902    (s.bind f).bind g = s.bind (λa, (f a).bind g) :=
id      └───┘  └──┘    └───┘        └──┘  
src      └───┘   └──┘      └───┘           └──┘
typ     └───┘  └──┘    └───┘        └──┘  
doc      └───┘   └──┘       └───┘           └──┘
903  multiset.induction_on s (by simp) (by simp {contextual := tt})
id   └───────────────────┘                                    └┘
src  └───────────────────┘       └──┘      └───┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └───┘ └────────────┘└┘
doc                              └──┘      └───┘ └────────────┘  
txt                              └──┘      └───┘ └────────────┘  
par                              └──┘      └───┘ └────────────┘  
pid                                             └────────────┘  
st                              └───┘     └──────────────────────┘
904  
905  lemma bind_bind (m : multiset α) (n : multiset β) {f : α → β → multiset γ} :
id                        └──────┘        └──────┘              └──────┘ 
src                       └──────┘         └──────┘                 └──────┘
typ                       └──────┘        └──────┘              └──────┘ 
doc                       └──────┘         └──────┘                 └──────┘
906    (bind m $ λa, bind n $ λb, f a b) = (bind n $ λb, bind m $ λa, f a b) :=
id      └──┘       └──┘             └──┘       └──┘         
src     └──┘         └──┘                  └──┘         └──┘
typ     └──┘       └──┘             └──┘       └──┘         
doc     └──┘         └──┘                   └──┘         └──┘
907  multiset.induction_on m (by simp) (by simp {contextual := tt})
id   └───────────────────┘                                    └┘
src  └───────────────────┘       └──┘      └───┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └───┘ └────────────┘└┘
doc                              └──┘      └───┘ └────────────┘  
txt                              └──┘      └───┘ └────────────┘  
par                              └──┘      └───┘ └────────────┘  
pid                                             └────────────┘  
st                              └───┘     └──────────────────────┘
908  
909  lemma bind_map_comm (m : multiset α) (n : multiset β) {f : α → β → γ} :
id                            └──────┘        └──────┘              
src                           └──────┘         └──────┘
typ                           └──────┘        └──────┘              
doc                           └──────┘         └──────┘
910    (bind m $ λa, n.map $ λb, f a b) = (bind n $ λb, m.map $ λa, f a b) :=
id      └──┘       └──┘            └──┘       └──┘        
src     └──┘          └──┘                └──┘          └──┘
typ     └──┘       └──┘            └──┘       └──┘        
doc     └──┘          └──┘                 └──┘          └──┘
911  multiset.induction_on m (by simp) (by simp {contextual := tt})
id   └───────────────────┘                                    └┘
src  └───────────────────┘       └──┘      └───┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └───┘ └────────────┘└┘
doc                              └──┘      └───┘ └────────────┘  
txt                              └──┘      └───┘ └────────────┘  
par                              └──┘      └───┘ └────────────┘  
pid                                             └────────────┘  
st                              └───┘     └──────────────────────┘
912  
913  @[simp, to_additive]
doc    └──┘  └─────────┘
914  lemma prod_bind [comm_monoid β] (s : multiset α) (t : α → multiset β) :
id                    └─────────┘        └──────┘           └──────┘ 
src                   └─────────┘         └──────┘             └──────┘
typ                   └─────────┘        └──────┘           └──────┘ 
doc                                       └──────┘             └──────┘
915    prod (bind s t) = prod (s.map $ λa, prod (t a)) :=
id     └──┘  └──┘     └──┘  └──┘      └──┘   
src    └──┘  └──┘       └──┘   └──┘       └──┘
typ    └──┘  └──┘     └──┘  └──┘      └──┘   
doc    └──┘  └──┘        └──┘   └──┘       └──┘
916  multiset.induction_on s (by simp) (assume a s ih, by simp [ih, cons_bind])
id   └───────────────────┘                      └┘           └┘  └───────┘
src  └───────────────────┘       └──┘                     └────┘  └┘└───────┘
typ  └───────────────────┘      └──┘            └┘     └────┘└┘└┘└───────┘
doc                              └──┘                     └────┘  └┘         
txt                              └──┘                     └────┘  └┘         
par                              └──┘                     └────┘  └┘         
pid                                                             └┘         
st                              └───┘                    └───────────────────┘
917  
918  /- product -/
919  
920  /-- The multiplicity of `(a, b)` in `product s t` is
921    the product of the multiplicity of `a` in `s` and `b` in `t`. -/
922  def product (s : multiset α) (t : multiset β) : multiset (α × β) :=
id                    └──────┘        └──────┘     └──────┘    
src                   └──────┘         └──────┘      └──────┘    
typ                   └──────┘        └──────┘     └──────┘    
doc                   └──────┘         └──────┘      └──────┘
923  s.bind $ λ a, t.map $ prod.mk a
id   └───┘       └──┘   └─────┘ 
src   └───┘         └──┘   └─────┘
typ  └───┘       └──┘   └─────┘ 
doc   └───┘         └──┘
924  
925  @[simp] theorem coe_product (l₁ : list α) (l₂ : list β) :
id                                     └──┘         └──┘ 
src                                    └──┘          └──┘
typ                                    └──┘         └──┘ 
doc    └──┘
926    @product α β l₁ l₂ = l₁.product l₂ :=
id      └─────┘   └┘ └┘  └┘└──────┘ └┘
src     └─────┘              └──────┘
typ     └─────┘   └┘ └┘  └┘└──────┘ └┘
doc     └─────┘               └──────┘
927  by rw [product, list.product, ← coe_bind]; simp
id          └─────┘  └──────────┘    └──────┘
src     └──┘└─────┘└┘└──────────┘└──┘└──────┘  └────
typ     └──┘└─────┘└┘└──────────┘└──┘└──────┘  └────
doc     └──┘└─────┘└┘└──────────┘└──┘          └────
txt     └──┘       └┘            └──┘          └────
par     └──┘       └┘            └──┘          └────
pid       └┘       └┘            └──┘              
st     └──────────┘└────────────┘└──────────┘└──────
928  
src  
typ  
doc  
txt  
par  
pid  
st   
929  @[simp] theorem zero_product (t) : @product α β 0 t = 0 := rfl
id                                       └─────┘            └─┘
src                                      └─────┘               └─┘
typ                                      └─────┘            └─┘
doc    └──┘                              └─────┘
930  
931  @[simp] theorem cons_product (a : α) (s : multiset α) (t : multiset β) :
id                                            └──────┘        └──────┘ 
src                                            └──────┘         └──────┘
typ                                           └──────┘        └──────┘ 
doc    └──┘                                    └──────┘         └──────┘
932    product (a :: s) t = map (prod.mk a) t + product s t :=
id     └─────┘   └┘     └─┘  └─────┘     └─────┘  
src    └─────┘    └┘       └─┘  └─────┘       └─────┘
typ    └─────┘   └┘     └─┘  └─────┘     └─────┘  
doc    └─────┘    └┘        └─┘                 └─────┘
933  by simp [product]
id            └─────┘
src     └────┘└─────┘└─
typ     └────┘└─────┘└─
doc     └────┘└─────┘└─
txt     └────┘       └─
par     └────┘       └─
pid                
st     └───────────────
934  
src  
typ  
doc  
txt  
par  
pid  
st   
935  @[simp] theorem product_singleton (a : α) (b : β) : product (a::0) (b::0) = (a,b)::0 := rfl
id                                                     └─────┘  └┘    └┘      └┘     └─┘
src                                                      └─────┘   └┘     └┘        └┘     └─┘
typ                                                    └─────┘  └┘    └┘      └┘     └─┘
doc    └──┘                                              └─────┘   └┘     └┘          └┘
936  
937  @[simp] theorem add_product (s t : multiset α) (u : multiset β) :
id                                      └──────┘        └──────┘ 
src                                     └──────┘         └──────┘
typ                                     └──────┘        └──────┘ 
doc    └──┘                             └──────┘         └──────┘
938    product (s + t) u = product s u + product t u :=
id     └─────┘        └─────┘    └─────┘  
src    └─────┘           └─────┘      └─────┘
typ    └─────┘        └─────┘    └─────┘  
doc    └─────┘             └─────┘       └─────┘
939  by simp [product]
id            └─────┘
src     └────┘└─────┘└─
typ     └────┘└─────┘└─
doc     └────┘└─────┘└─
txt     └────┘       └─
par     └────┘       └─
pid                
st     └───────────────
940  
src  
typ  
doc  
txt  
par  
pid  
st   
941  @[simp] theorem product_add (s : multiset α) : ∀ t u : multiset β,
id                                    └──────┘             └──────┘ 
src                                   └──────┘              └──────┘
typ                                   └──────┘             └──────┘ 
doc    └──┘                           └──────┘              └──────┘
942    product s (t + u) = product s t + product s u :=
id     └─────┘        └─────┘    └─────┘  
src    └─────┘           └─────┘      └─────┘
typ    └─────┘        └─────┘    └─────┘  
doc    └─────┘             └─────┘       └─────┘
943  multiset.induction_on s (λ t u, rfl) $ λ a s IH t u,
id   └───────────────────┘        └─┘        └┘  
src  └───────────────────┘           └─┘
typ  └───────────────────┘        └─┘        └┘  
944    by rw [cons_product, IH]; simp
id            └──────────┘  └┘
src       └──┘└──────────┘└┘    └────
typ       └──┘└──────────┘└┘└┘  └────
doc       └──┘            └┘    └────
txt       └──┘            └┘    └────
par       └──┘            └┘    └────
pid         └┘            └┘        
st       └───────────────┘└──┘└──────
945  
src  
typ  
doc  
txt  
par  
pid  
st   
946  @[simp] theorem mem_product {s t} : ∀ {p : α × β}, p ∈ @product α β s t ↔ p.1 ∈ s ∧ p.2 ∈ t
id                                                     └─────┘              
src                                                        └─────┘                    
typ                                                    └─────┘              
doc    └──┘                                                  └─────┘
947  | (a, b) := by simp [product, and.left_comm]
id                       └─────┘  └───────────┘
src                └────┘└─────┘└┘└───────────┘└─
typ                └────┘└─────┘└┘└───────────┘└─
doc                 └────┘└─────┘└┘             └─
txt                 └────┘       └┘             └─
par                 └────┘       └┘             └─
pid                            └┘             
st                 └──────────────────────────────
948  
src  
typ  
doc  
txt  
par  
pid  
st   
949  @[simp] theorem card_product (s : multiset α) (t : multiset β) : card (product s t) = card s * card t :=
id                                     └──────┘        └──────┘     └──┘  └─────┘     └──┘   └──┘ 
src                                    └──────┘         └──────┘      └──┘  └─────┘       └──┘    └──┘
typ                                    └──────┘        └──────┘     └──┘  └─────┘     └──┘   └──┘ 
doc    └──┘                            └──────┘         └──────┘      └──┘  └─────┘        └──┘     └──┘
950  by simp [product, repeat, (∘), mul_comm]
id            └─────┘  └────┘      └──────┘
src     └────┘└─────┘└┘└────┘└┘└──┘└──────┘└─
typ     └────┘└─────┘└┘└────┘└┘└──┘└──────┘└─
doc     └────┘└─────┘└┘└────┘└┘ └──┘        └─
txt     └────┘       └┘      └┘ └──┘        └─
par     └────┘       └┘      └┘ └──┘        └─
pid                └┘      └┘ └──┘        
st     └──────────────────────────────────────
951  
src  
typ  
doc  
txt  
par  
pid  
st   
952  /- sigma -/
src  ───────────┘
typ  ───────────┘
doc  ───────────┘
txt  ───────────┘
par  ───────────┘
pid  ───────────┘
st   ───────────┘
953  section
954  variable {σ : α → Type*}
955  
956  /-- `sigma s t` is the dependent version of `product`. It is the sum of
957    `(a, b)` as `a` ranges over `s` and `b` ranges over `t a`. -/
958  protected def sigma (s : multiset α) (t : Π a, multiset (σ a)) : multiset (Σ a, σ a) :=
id                            └──────┘            └──────┘        └──────┘     
src                           └──────┘              └──────┘          └──────┘    
typ                           └──────┘            └──────┘        └──────┘     
doc                           └──────┘              └──────┘          └──────┘
959  s.bind $ λ a, (t a).map $ sigma.mk a
id   └───┘          └─┘    └──────┘ 
src   └───┘             └─┘    └──────┘
typ  └───┘          └─┘    └──────┘ 
doc   └───┘             └─┘
960  
961  @[simp] theorem coe_sigma (l₁ : list α) (l₂ : Π a, list (σ a)) :
id                                   └──┘             └──┘   
src                                  └──┘               └──┘
typ                                  └──┘             └──┘   
doc    └──┘
962    @multiset.sigma α σ l₁ (λ a, l₂ a) = l₁.sigma l₂ :=
id      └────────────┘   └┘      └┘    └┘└────┘ └┘
src     └────────────┘                       └────┘
typ     └────────────┘   └┘      └┘    └┘└────┘ └┘
doc     └────────────┘                        └────┘
963  by rw [multiset.sigma, list.sigma, ← coe_bind]; simp
id          └────────────┘  └────────┘    └──────┘
src     └──┘└────────────┘└┘└────────┘└──┘└──────┘  └────
typ     └──┘└────────────┘└┘└────────┘└──┘└──────┘  └────
doc     └──┘└────────────┘└┘└────────┘└──┘          └────
txt     └──┘              └┘          └──┘          └────
par     └──┘              └┘          └──┘          └────
pid       └┘              └┘          └──┘              
st     └─────────────────┘└──────────┘└──────────┘└──────
964  
src  
typ  
doc  
txt  
par  
pid  
st   
965  @[simp] theorem zero_sigma (t) : @multiset.sigma α σ 0 t = 0 := rfl
id                                     └────────────┘            └─┘
src                                    └────────────┘               └─┘
typ                                    └────────────┘            └─┘
doc    └──┘                            └────────────┘
966  
967  @[simp] theorem cons_sigma (a : α) (s : multiset α) (t : Π a, multiset (σ a)) :
id                                          └──────┘            └──────┘   
src                                          └──────┘              └──────┘
typ                                         └──────┘            └──────┘   
doc    └──┘                                  └──────┘              └──────┘
968    (a :: s).sigma t = map (sigma.mk a) (t a) + s.sigma t :=
id       └┘  └───┘    └─┘  └──────┘        └────┘ 
src       └┘   └───┘     └─┘  └──────┘            └────┘
typ      └┘  └───┘    └─┘  └──────┘        └────┘ 
doc       └┘   └───┘      └─┘                       └────┘
969  by simp [multiset.sigma]
id            └────────────┘
src     └────┘└────────────┘└─
typ     └────┘└────────────┘└─
doc     └────┘└────────────┘└─
txt     └────┘              └─
par     └────┘              └─
pid                       
st     └──────────────────────
970  
src  
typ  
doc  
txt  
par  
pid  
st   
971  @[simp] theorem sigma_singleton (a : α) (b : α → β) :
id                                                  
typ                                                 
doc    └──┘
972    (a::0).sigma (λ a, b a::0) = ⟨a, b a⟩::0 := rfl
id      └┘  └───┘        └┘         └┘     └─┘
src      └┘  └───┘           └┘            └┘     └─┘
typ     └┘  └───┘        └┘         └┘     └─┘
doc      └┘  └───┘           └┘             └┘
973  
974  @[simp] theorem add_sigma (s t : multiset α) (u : Π a, multiset (σ a)) :
id                                    └──────┘            └──────┘   
src                                   └──────┘              └──────┘
typ                                   └──────┘            └──────┘   
doc    └──┘                           └──────┘              └──────┘
975    (s + t).sigma u = s.sigma u + t.sigma u :=
id         └───┘    └────┘   └────┘ 
src          └───┘      └────┘     └────┘
typ        └───┘    └────┘   └────┘ 
doc           └───┘       └────┘      └────┘
976  by simp [multiset.sigma]
id            └────────────┘
src     └────┘└────────────┘└─
typ     └────┘└────────────┘└─
doc     └────┘└────────────┘└─
txt     └────┘              └─
par     └────┘              └─
pid                       
st     └──────────────────────
977  
src  
typ  
doc  
txt  
par  
pid  
st   
978  @[simp] theorem sigma_add (s : multiset α) : ∀ t u : Π a, multiset (σ a),
id                                  └──────┘                 └──────┘   
src                                 └──────┘                   └──────┘
typ                                 └──────┘                 └──────┘   
doc    └──┘                         └──────┘                   └──────┘
979    s.sigma (λ a, t a + u a) = s.sigma t + s.sigma u :=
id     └────┘             └────┘   └────┘ 
src     └────┘                   └────┘     └────┘
typ    └────┘             └────┘   └────┘ 
doc     └────┘                     └────┘      └────┘
980  multiset.induction_on s (λ t u, rfl) $ λ a s IH t u,
id   └───────────────────┘        └─┘        └┘  
src  └───────────────────┘           └─┘
typ  └───────────────────┘        └─┘        └┘  
981    by rw [cons_sigma, IH]; simp
id            └────────┘  └┘
src       └──┘└────────┘└┘    └────
typ       └──┘└────────┘└┘└┘  └────
doc       └──┘          └┘    └────
txt       └──┘          └┘    └────
par       └──┘          └┘    └────
pid         └┘          └┘        
st       └─────────────┘└──┘└──────
982  
src  
typ  
doc  
txt  
par  
pid  
st   
983  @[simp] theorem mem_sigma {s t} : ∀ {p : Σ a, σ a},
id                                              
src                                             
typ                                             
doc    └──┘
984    p ∈ @multiset.sigma α σ s t ↔ p.1 ∈ s ∧ p.2 ∈ t p.1
id        └────────────┘               
src        └────────────┘                        
typ       └────────────┘               
doc         └────────────┘
985  | ⟨a, b⟩ := by simp [multiset.sigma, and_assoc, and.left_comm]
id                        └────────────┘  └───────┘  └───────────┘
src                 └────┘└────────────┘└┘└───────┘└┘└───────────┘└─
typ                 └────┘└────────────┘└┘└───────┘└┘└───────────┘└─
doc                 └────┘└────────────┘└┘         └┘             └─
txt                 └────┘              └┘         └┘             └─
par                 └────┘              └┘         └┘             └─
pid                                   └┘         └┘             
st                 └────────────────────────────────────────────────
986  
src  
typ  
doc  
txt  
par  
pid  
st   
987  @[simp] theorem card_sigma (s : multiset α) (t : Π a, multiset (σ a)) :
id                                   └──────┘            └──────┘   
src                                  └──────┘              └──────┘
typ                                  └──────┘            └──────┘   
doc    └──┘                          └──────┘              └──────┘
988    card (s.sigma t) = sum (map (λ a, card (t a)) s) :=
id     └──┘  └────┘    └─┘  └─┘      └──┘      
src    └──┘   └────┘     └─┘  └─┘       └──┘
typ    └──┘  └────┘    └─┘  └─┘      └──┘      
doc    └──┘   └────┘           └─┘       └──┘
989  by simp [multiset.sigma, (∘)]
id            └────────────┘  
src     └────┘└────────────┘└┘└───
typ     └────┘└────────────┘└┘└───
doc     └────┘└────────────┘└┘ └───
txt     └────┘              └┘ └───
par     └────┘              └┘ └───
pid                       └┘ └─┘
st     └───────────────────────────
990  
src  
typ  
doc  
txt  
par  
pid  
st   
991  end
992  
993  /- map for partial functions -/
994  
995  /-- Lift of the list `pmap` operation. Map a partial function `f` over a multiset
996    `s` whose elements are all in the domain of `f`. -/
997  def pmap {p : α → Prop} (f : Π a, p a → β) (s : multiset α) : (∀ a ∈ s, p a) → multiset β :=
id                                              └──────┘                  └──────┘ 
src                                                  └──────┘                       └──────┘
typ                                             └──────┘                  └──────┘ 
doc                                                  └──────┘                       └──────┘
998  quot.rec_on s (λ l H, ↑(pmap f l H)) $ λ l₁ l₂ (pp : l₁ ~ l₂),
id   └─────────┘         └──┘          └┘ └┘       └┘  └┘
src  └─────────┘            └──┘                            
typ  └─────────┘         └──┘          └┘ └┘       └┘  └┘
doc                          └──┘                            
999  funext $ λ (H₂ : ∀ a ∈ l₂, p a),
id   └────┘                └┘   
src  └────┘
typ  └────┘                └┘   
1000  have H₁ : ∀ a ∈ l₁, p a, from λ a h, H₂ a ((mem_of_perm pp).1 h),
id                  └┘               └┘    └─────────┘ └┘   
src                                              └─────────┘    
typ                 └┘               └┘    └─────────┘ └┘   
1001  have ∀ {s₂ e H}, @eq.rec (multiset α) l₁
id           └┘      └────┘  └──────┘   └┘
src                    └────┘  └──────┘
typ          └┘      └────┘  └──────┘   └┘
doc                            └──────┘
1002    (λ s, (∀ a ∈ s, p a) → multiset β) (λ _, ↑(pmap f l₁ H₁))
id                       └──────┘         └──┘  └┘ └┘
src                           └──────┘           └──┘
typ                      └──────┘         └──┘  └┘ └┘
doc                           └──────┘            └──┘
1003    s₂ e H = ↑(pmap f l₁ H₁), by intros s₂ e _; subst e,
id     └┘     └──┘  └┘ └┘                           
src             └──┘              └───────────┘  └────┘
typ    └┘     └──┘  └┘ └┘      └───────────┘  └────┘
doc               └──┘              └───────────┘  └────┘
txt                                 └───────────┘  └────┘
par                                 └───────────┘  └────┘
pid                                       └─────┘       
st                                 └─────────────────────┘
1004  this.trans $ quot.sound $ perm_pmap f pp
id   └──┘└────┘   └────────┘   └───────┘  └┘
src      └────┘   └────────┘   └───────┘
typ  └──┘└────┘   └────────┘   └───────┘  └┘
1005  
1006  @[simp] theorem coe_pmap {p : α → Prop} (f : Π a, p a → β)
id                                                       
typ                                                      
doc    └──┘
1007    (l : list α) (H : ∀ a ∈ l, p a) : pmap f l H = l.pmap f H := rfl
id          └──┘                    └──┘     └───┘      └─┘
src         └──┘                         └──┘         └───┘        └─┘
typ         └──┘                    └──┘     └───┘      └─┘
doc                                      └──┘          └───┘
1008  
1009  @[simp] lemma pmap_zero {p : α → Prop} (f : Π a, p a → β) (h : ∀a∈(0:multiset α), p a) :
id                                                                  └──────┘     
src                                                                       └──────┘
typ                                                                 └──────┘     
doc    └──┘                                                               └──────┘
1010    pmap f 0 h = 0 := rfl
id     └──┘           └─┘
src    └──┘             └─┘
typ    └──┘           └─┘
doc    └──┘
1011  
1012  @[simp] lemma pmap_cons {p : α → Prop} (f : Π a, p a → β) (a : α) (m : multiset α) :
id                                                                    └──────┘ 
src                                                                         └──────┘
typ                                                                   └──────┘ 
doc    └──┘                                                                 └──────┘
1013    ∀(h : ∀b∈a::m, p b), pmap f (a :: m) h =
id             └┘      └──┘    └┘    
src              └┘         └──┘      └┘      
typ            └┘      └──┘    └┘    
doc              └┘         └──┘      └┘
1014      f a (h a (mem_cons_self a m)) :: pmap f m (λa ha, h a $ mem_cons_of_mem ha) :=
id             └───────────┘     └┘ └──┘      └┘      └─────────────┘ └┘
src                └───────────┘       └┘ └──┘                   └─────────────┘
typ            └───────────┘     └┘ └──┘      └┘      └─────────────┘ └┘
doc                                    └┘ └──┘
1015  quotient.induction_on m $ assume l h, rfl
id   └───────────────────┘              └─┘
src  └───────────────────┘                 └─┘
typ  └───────────────────┘              └─┘
1016  
1017  /-- "Attach" a proof that `a ∈ s` to each element `a` in `s` to produce
1018    a multiset on `{x // x ∈ s}`. -/
1019  def attach (s : multiset α) : multiset {x // x ∈ s} := pmap subtype.mk s (λ a, id)
id                   └──────┘     └──────┘            └──┘ └────────┘       └┘
src                  └──────┘      └──────┘               └──┘ └────────┘         └┘
typ                  └──────┘     └──────┘            └──┘ └────────┘       └┘
doc                  └──────┘      └──────┘                 └──┘
1020  
1021  @[simp] theorem coe_attach (l : list α) :
id                                   └──┘ 
src                                  └──┘
typ                                  └──┘ 
doc    └──┘
1022   @eq (multiset {x // x ∈ l}) (@attach α l) l.attach := rfl
id     └┘  └──────┘            └────┘    └─────┘    └─┘
src    └┘  └──────┘               └────┘       └─────┘    └─┘
typ    └┘  └──────┘            └────┘    └─────┘    └─┘
doc        └──────┘                 └────┘       └─────┘
1023  
1024  theorem pmap_eq_map (p : α → Prop) (f : α → β) (s : multiset α) :
id                                                    └──────┘ 
src                                                      └──────┘
typ                                                   └──────┘ 
doc                                                      └──────┘
1025    ∀ H, @pmap _ _ p (λ a _, f a) s H = map f s :=
id          └──┘                  └─┘  
src          └──┘                         └─┘
typ         └──┘                  └─┘  
doc          └──┘                          └─┘
1026  quot.induction_on s $ λ l H, congr_arg coe $ pmap_eq_map p f l H
id   └───────────────┘         └───────┘ └─┘   └─────────┘    
src  └───────────────┘            └───────┘ └─┘   └─────────┘
typ  └───────────────┘         └───────┘ └─┘   └─────────┘    
1027  
1028  theorem pmap_congr {p q : α → Prop} {f : Π a, p a → β} {g : Π a, q a → β}
id                                                                  
typ                                                                 
1029    (s : multiset α) {H₁ H₂} (h : ∀ a h₁ h₂, f a h₁ = g a h₂) :
id          └──────┘                   └┘ └┘    └┘    └┘
src         └──────┘                                   
typ         └──────┘                   └┘ └┘    └┘    └┘
doc         └──────┘
1030    pmap f s H₁ = pmap g s H₂ :=
id     └──┘   └┘  └──┘   └┘
src    └──┘         └──┘
typ    └──┘   └┘  └──┘   └┘
doc    └──┘          └──┘
1031  quot.induction_on s (λ l H₁ H₂, congr_arg coe $ pmap_congr l h) H₁ H₂
id   └───────────────┘      └┘ └┘  └───────┘ └─┘   └────────┘    └┘ └┘
src  └───────────────┘               └───────┘ └─┘   └────────┘
typ  └───────────────┘      └┘ └┘  └───────┘ └─┘   └────────┘    └┘ └┘
1032  
1033  theorem map_pmap {p : α → Prop} (g : β → γ) (f : Π a, p a → β)
id                                                         
typ                                                        
1034    (s) : ∀ H, map g (pmap f s H) = pmap (λ a h, g (f a h)) s H :=
id               └─┘   └──┘      └──┘               
src               └─┘    └──┘         └──┘
typ              └─┘   └──┘      └──┘               
doc               └─┘    └──┘          └──┘
1035  quot.induction_on s $ λ l H, congr_arg coe $ map_pmap g f l H
id   └───────────────┘         └───────┘ └─┘   └──────┘    
src  └───────────────┘            └───────┘ └─┘   └──────┘
typ  └───────────────┘         └───────┘ └─┘   └──────┘    
1036  
1037  theorem pmap_eq_map_attach {p : α → Prop} (f : Π a, p a → β)
id                                                         
typ                                                        
1038    (s) : ∀ H, pmap f s H = s.attach.map (λ x, f x.1 (H _ x.2)) :=
id               └──┘     └─────┘└──┘             
src               └──┘         └─────┘└──┘                  
typ              └──┘     └─────┘└──┘             
doc               └──┘          └─────┘└──┘
1039  quot.induction_on s $ λ l H, congr_arg coe $ pmap_eq_map_attach f l H
id   └───────────────┘         └───────┘ └─┘   └────────────────┘   
src  └───────────────┘            └───────┘ └─┘   └────────────────┘
typ  └───────────────┘         └───────┘ └─┘   └────────────────┘   
1040  
1041  theorem attach_map_val (s : multiset α) : s.attach.map subtype.val = s :=
id                               └──────┘     └─────┘└──┘ └─────────┘  
src                              └──────┘       └─────┘└──┘ └─────────┘ 
typ                              └──────┘     └─────┘└──┘ └─────────┘  
doc                              └──────┘       └─────┘└──┘
1042  quot.induction_on s $ λ l, congr_arg coe $ attach_map_val l
id   └───────────────┘        └───────┘ └─┘   └────────────┘ 
src  └───────────────┘          └───────┘ └─┘   └────────────┘
typ  └───────────────┘        └───────┘ └─┘   └────────────┘ 
1043  
1044  @[simp] theorem mem_attach (s : multiset α) : ∀ x, x ∈ s.attach :=
id                                   └──────┘           └─────┘
src                                  └──────┘               └─────┘
typ                                  └──────┘           └─────┘
doc    └──┘                          └──────┘                └─────┘
1045  quot.induction_on s $ λ l, mem_attach _
id   └───────────────┘        └────────┘
src  └───────────────┘          └────────┘
typ  └───────────────┘        └────────┘
1046  
1047  @[simp] theorem mem_pmap {p : α → Prop} {f : Π a, p a → β}
id                                                       
typ                                                      
doc    └──┘
1048    {s H b} : b ∈ pmap f s H ↔ ∃ a (h : a ∈ s), f a (H a h) = b :=
id                 └──┘                        
src                 └──┘                                  
typ                └──┘                        
doc                  └──┘
1049  quot.induction_on s (λ l H, mem_pmap) H
id   └───────────────┘        └──────┘  
src  └───────────────┘           └──────┘
typ  └───────────────┘        └──────┘  
1050  
1051  @[simp] theorem card_pmap {p : α → Prop} (f : Π a, p a → β)
id                                                        
typ                                                       
doc    └──┘
1052    (s H) : card (pmap f s H) = card s :=
id             └──┘  └──┘      └──┘ 
src            └──┘  └──┘         └──┘
typ            └──┘  └──┘      └──┘ 
doc            └──┘  └──┘          └──┘
1053  quot.induction_on s (λ l H, length_pmap) H
id   └───────────────┘        └─────────┘  
src  └───────────────┘           └─────────┘
typ  └───────────────┘        └─────────┘  
1054  
1055  @[simp] theorem card_attach {m : multiset α} : card (attach m) = card m := card_pmap _ _ _
id                                    └──────┘     └──┘  └────┘    └──┘     └───────┘
src                                   └──────┘      └──┘  └────┘     └──┘      └───────┘
typ                                   └──────┘     └──┘  └────┘    └──┘     └───────┘
doc    └──┘                           └──────┘      └──┘  └────┘      └──┘
1056  
1057  @[simp] lemma attach_zero : (0 : multiset α).attach = 0 := rfl
id                                    └──────┘  └────┘        └─┘
src                                   └──────┘   └────┘        └─┘
typ                                   └──────┘  └────┘        └─┘
doc    └──┘                           └──────┘   └────┘
1058  
1059  lemma attach_cons (a : α) (m : multiset α) :
id                                 └──────┘ 
src                                 └──────┘
typ                                └──────┘ 
doc                                 └──────┘
1060    (a :: m).attach = ⟨a, mem_cons_self a m⟩ :: (m.attach.map $ λp, ⟨p.1, mem_cons_of_mem p.2⟩) :=
id       └┘  └────┘      └───────────┘    └┘  └─────┘└──┘          └─────────────┘ 
src       └┘   └────┘       └───────────┘      └┘   └─────┘└──┘            └─────────────┘  
typ      └┘  └────┘      └───────────┘    └┘  └─────┘└──┘          └─────────────┘ 
doc       └┘   └────┘                           └┘   └─────┘└──┘
1061  quotient.induction_on m $ assume l, congr_arg coe $ congr_arg (list.cons _) $
id   └───────────────────┘             └───────┘ └─┘   └───────┘  └───────┘
src  └───────────────────┘               └───────┘ └─┘   └───────┘  └───────┘
typ  └───────────────────┘             └───────┘ └─┘   └───────┘  └───────┘
1062    by rw [list.map_pmap]; exact list.pmap_congr _ (assume a' h₁ h₂, subtype.eq rfl)
id            └───────────┘         └─────────────┘                     └────────┘ └─┘
src       └──┘└───────────┘  └────┘└─────────────┘└─┘       └─────────┘└────────┘└─┘└─
typ       └──┘└───────────┘  └────┘└─────────────┘└─┘       └─────────┘└────────┘└─┘└─
doc       └──┘               └────┘               └─┘       └─────────┘             └─
txt       └──┘               └────┘               └─┘       └─────────┘             └─
par       └──┘               └────┘               └─┘       └─────────┘             └─
pid         └┘                                   └─┘       └─────────┘             
st       └────────────────┘└───────────────────────────────────────────────────────────
1063  
src  
typ  
doc  
txt  
par  
pid  
st   
1064  section decidable_pi_exists
1065  variables {m : multiset α}
id                  └──────┘
src                 └──────┘
typ                 └──────┘
doc                 └──────┘
1066  
1067  protected def decidable_forall_multiset {p : α → Prop} [hp : ∀a, decidable (p a)] :
id                                                                  └───────┘   
src                                                                   └───────┘
typ                                                                 └───────┘   
1068    decidable (∀a∈m, p a) :=
id     └───────┘       
src    └───────┘
typ    └───────┘       
1069  quotient.rec_on_subsingleton m (λl, decidable_of_iff (∀a∈l, p a) $ by simp)
id   └──────────────────────────┘      └──────────────┘       
src  └──────────────────────────┘        └──────────────┘                  └──┘
typ  └──────────────────────────┘      └──────────────┘              └──┘
doc                                                                        └──┘
txt                                                                        └──┘
par                                                                        └──┘
st                                                                        └───┘
1070  
1071  instance decidable_dforall_multiset {p : Πa∈m, Prop} [hp : ∀a (h : a ∈ m), decidable (p a h)] :
id                                                                        └───────┘    
src                                                                            └───────┘
typ                                                                       └───────┘    
1072    decidable (∀a (h : a ∈ m), p a h) :=
id     └───────┘                
src    └───────┘            
typ    └───────┘                
1073  decidable_of_decidable_of_iff
id   └───────────────────────────┘
src  └───────────────────────────┘
typ  └───────────────────────────┘
1074    (@multiset.decidable_forall_multiset {a // a ∈ m} m.attach (λa, p a.1 a.2) _)
id       └────────────────────────────────┘         └─────┘        
src      └────────────────────────────────┘             └─────┘            
typ      └────────────────────────────────┘         └─────┘        
doc                                                       └─────┘
1075    (iff.intro (assume h a ha, h ⟨a, ha⟩ (mem_attach _ _)) (assume h ⟨a, ha⟩ _, h _ _))
id      └───────┘           └┘      └┘   └────────┘                         
src     └───────┘                            └────────┘
typ     └───────┘           └┘      └┘   └────────┘                         
1076  
1077  /-- decidable equality for functions whose domain is bounded by multisets -/
1078  instance decidable_eq_pi_multiset {β : α → Type*} [h : ∀a, decidable_eq (β a)] :
id                                                            └──────────┘   
src                                                             └──────────┘
typ                                                           └──────────┘   
1079    decidable_eq (Πa∈m, β a) :=
id     └──────────┘       
src    └──────────┘
typ    └──────────┘       
1080  assume f g, decidable_of_iff (∀a (h : a ∈ m), f a h = g a h) (by simp [function.funext_iff])
id             └──────────────┘                                └─────────────────┘
src              └──────────────┘                                   └────┘└─────────────────┘
typ            └──────────────┘                          └────┘└─────────────────┘
doc                                                                   └────┘                   
txt                                                                   └────┘                   
par                                                                   └────┘                   
pid                                                                                          
st                                                                   └─────────────────────────┘
1081  
1082  def decidable_exists_multiset {p : α → Prop} [decidable_pred p] :
id                                                └────────────┘ 
src                                                └────────────┘
typ                                               └────────────┘ 
1083    decidable (∃ x ∈ m, p x) :=
id     └───────┘        
src    └───────┘        
typ    └───────┘        
1084  quotient.rec_on_subsingleton m list.decidable_exists_mem
id   └──────────────────────────┘  └───────────────────────┘
src  └──────────────────────────┘   └───────────────────────┘
typ  └──────────────────────────┘  └───────────────────────┘
1085  
1086  instance decidable_dexists_multiset {p : Πa∈m, Prop} [hp : ∀a (h : a ∈ m), decidable (p a h)] :
id                                                                        └───────┘    
src                                                                            └───────┘
typ                                                                       └───────┘    
1087    decidable (∃a (h : a ∈ m), p a h) :=
id     └───────┘              
src    └───────┘              
typ    └───────┘              
1088  decidable_of_decidable_of_iff
id   └───────────────────────────┘
src  └───────────────────────────┘
typ  └───────────────────────────┘
1089    (@multiset.decidable_exists_multiset {a // a ∈ m} m.attach (λa, p a.1 a.2) _)
id       └────────────────────────────────┘         └─────┘        
src      └────────────────────────────────┘             └─────┘            
typ      └────────────────────────────────┘         └─────┘        
doc                                                       └─────┘
1090    (iff.intro (λ ⟨⟨a, ha₁⟩, _, ha₂⟩, ⟨a, ha₁, ha₂⟩)
id      └───────┘       └─┘      └─┘
src     └───────┘
typ     └───────┘       └─┘      └─┘
1091      (λ ⟨a, ha₁, ha₂⟩, ⟨⟨a, ha₁⟩, mem_attach _ _, ha₂⟩))
id            └─┘  └─┘              └────────┘
src                                   └────────┘
typ           └─┘  └─┘              └────────┘
1092  
1093  end decidable_pi_exists
1094  
1095  /- subtraction -/
1096  section
1097  variables [decidable_eq α] {s t u : multiset α} {a b : α}
id              └──────────┘             └──────┘
src             └──────────┘             └──────┘
typ             └──────────┘             └──────┘
doc                                      └──────┘
1098  
1099  /-- `s - t` is the multiset such that
1100    `count a (s - t) = count a s - count a t` for all `a`. -/
1101  protected def sub (s t : multiset α) : multiset α :=
id                            └──────┘     └──────┘ 
src                           └──────┘      └──────┘
typ                           └──────┘     └──────┘ 
doc                           └──────┘      └──────┘
1102  quotient.lift_on₂ s t (λ l₁ l₂, (l₁.diff l₂ : multiset α)) $ λ v₁ v₂ w₁ w₂ p₁ p₂,
id   └───────────────┘      └┘ └┘   └┘└───┘ └┘   └──────┘        └┘ └┘ └┘ └┘ └┘ └┘
src  └───────────────┘                  └───┘      └──────┘
typ  └───────────────┘      └┘ └┘   └┘└───┘ └┘   └──────┘        └┘ └┘ └┘ └┘ └┘ └┘
doc                                                └──────┘
1103    quot.sound $ perm_diff_right w₁ p₂ ▸ perm_diff_left _ p₁
id     └────────┘   └─────────────┘ └┘ └┘  └────────────┘   └┘
src    └────────┘   └─────────────┘        └────────────┘
typ    └────────┘   └─────────────┘ └┘ └┘  └────────────┘   └┘
1104  
1105  instance : has_sub (multiset α) := ⟨multiset.sub⟩
id              └─────┘  └──────┘       └──────────┘
src             └─────┘  └──────┘        └──────────┘
typ             └─────┘  └──────┘       └──────────┘
doc                      └──────┘        └──────────┘
1106  
1107  @[simp] theorem coe_sub (s t : list α) : (s - t : multiset α) = (s.diff t : list α) := rfl
id                                  └──┘           └──────┘     └───┘    └──┘      └─┘
src                                 └──┘              └──────┘       └───┘     └──┘       └─┘
typ                                 └──┘           └──────┘     └───┘    └──┘      └─┘
doc    └──┘                                            └──────┘
1108  
1109  theorem sub_eq_fold_erase (s t : multiset α) : s - t = foldl erase erase_comm s t :=
id                                    └──────┘         └───┘ └───┘ └────────┘  
src                                   └──────┘            └───┘ └───┘ └────────┘
typ                                   └──────┘         └───┘ └───┘ └────────┘  
doc                                   └──────┘              └───┘ └───┘
1110  quotient.induction_on₂ s t $ λ l₁ l₂,
id   └────────────────────┘       └┘ └┘
src  └────────────────────┘
typ  └────────────────────┘       └┘ └┘
1111  show ↑(l₁.diff l₂) = foldl erase erase_comm ↑l₁ ↑l₂,
id         └┘└───┘ └┘   └───┘ └───┘ └────────┘ └┘ └┘
src          └───┘      └───┘ └───┘ └────────┘    
typ        └┘└───┘ └┘   └───┘ └───┘ └────────┘ └┘ └┘
doc                       └───┘ └───┘
1112  by { rw diff_eq_foldl l₁ l₂, symmetry, exact foldl_hom _ _ _ _ _ (λ x y, rfl) }
id           └───────────┘ └┘ └┘                  └───────┘                   └─┘
src       └─┘└───────────┘      └──────┘  └────┘└───────┘└─────────┘  └────┘└─┘└┘
typ       └─┘└───────────┘└┘└┘  └──────┘  └────┘└───────┘└─────────┘  └────┘└─┘└┘
doc       └─┘                   └──────┘  └────┘         └─────────┘  └────┘   └┘
txt       └─┘                   └──────┘  └────┘         └─────────┘  └────┘   └┘
par       └─┘                   └──────┘  └────┘         └─────────┘  └────┘   └┘
pid                                                    └─────────┘  └────┘   
st     └───────────────────────┘└────────┘└───────────────────────────────────────┘└┘
1113  
1114  @[simp] theorem sub_zero (s : multiset α) : s - 0 = s :=
id                                 └──────┘          
src                                └──────┘           
typ                                └──────┘          
doc    └──┘                        └──────┘
1115  quot.induction_on s $ λ l, rfl
id   └───────────────┘        └─┘
src  └───────────────┘          └─┘
typ  └───────────────┘        └─┘
1116  
1117  @[simp] theorem sub_cons (a : α) (s t : multiset α) : s - a::t = s.erase a - t :=
id                                          └──────┘       └┘  └────┘   
src                                          └──────┘          └┘    └────┘   
typ                                         └──────┘       └┘  └────┘   
doc    └──┘                                  └──────┘           └┘     └────┘
1118  quotient.induction_on₂ s t $ λ l₁ l₂, congr_arg coe $ diff_cons _ _ _
id   └────────────────────┘       └┘ └┘  └───────┘ └─┘   └───────┘
src  └────────────────────┘                └───────┘ └─┘   └───────┘
typ  └────────────────────┘       └┘ └┘  └───────┘ └─┘   └───────┘
1119  
1120  theorem add_sub_of_le (h : s ≤ t) : s + (t - s) = t :=
id                                            
src                                               
typ                                           
1121  begin
st   └─────
1122    revert t,
src    └──────┘
typ    └──────┘
doc    └──────┘
txt    └──────┘
par    └──────┘
pid          └┘
st   ─────────┘└─
1123    refine multiset.induction_on s (by simp) (λ a s IH t h, _),
id            └───────────────────┘ 
src    └─────┘└───────────────────┘    └──┘└┘  └─────────────┘
typ    └─────┘└───────────────────┘   └──┘└┘  └─────────────┘
doc    └─────┘                         └──┘└┘  └─────────────┘
txt    └─────┘                         └──┘└┘  └─────────────┘
par    └─────┘                         └──┘└┘  └─────────────┘
pid                                   └─────┘  └─────────────┘
st   ───────────────────────────────────┘└───┘└─────────────────┘└─
1124    have := cons_erase (mem_of_le h (mem_cons_self _ _)),
id             └────────┘  └───────┘   └───────────┘
src    └──────┘└────────┘ └───────┘  └───────────┘└────┘
typ    └──────┘└────────┘ └───────┘ └───────────┘└────┘
doc    └──────┘                                   └────┘
txt    └──────┘                                   └────┘
par    └──────┘                                   └────┘
pid    └───┘└─┘                                   └────┘
st   ─────────────────────────────────────────────────────┘└─
1125    rw [cons_add, sub_cons, IH, this],
id         └──────┘  └──────┘      └──┘
src    └──┘└──────┘└┘└──────┘└┘  └┘    
typ    └──┘└──────┘└┘└──────┘└┘└┘└┘└──┘
doc    └──┘        └┘        └┘  └┘    
txt    └──┘        └┘        └┘  └┘    
par    └──┘        └┘        └┘  └┘    
pid      └┘        └┘        └┘  └┘    
st   ─────────────┘└────────┘└──┘└────┘└──
1126    exact (cons_le_cons_iff a).1 (this.symm ▸ h)
id            └──────────────┘      └───────┘  
src    └────┘ └──────────────┘ └──┘ └───────┘ └┘
typ    └────┘ └──────────────┘└──┘ └───────┘└┘
doc    └────┘                  └──┘            └┘
txt    └────┘                  └──┘            └┘
par    └────┘                  └──┘            └┘
pid                           └──┘            
st   ──────────────────────────────────────────────┘
1127  end
st   └─┘
1128  
1129  theorem sub_add' : s - (t + u) = s - t - u :=
id                                  
src                                     
typ                                 
1130  quotient.induction_on₃ s t u $
id   └────────────────────┘   
src  └────────────────────┘
typ  └────────────────────┘   
1131  λ l₁ l₂ l₃, congr_arg coe $ diff_append _ _ _
id     └┘ └┘ └┘  └───────┘ └─┘   └─────────┘
src              └───────┘ └─┘   └─────────┘
typ    └┘ └┘ └┘  └───────┘ └─┘   └─────────┘
1132  
1133  theorem sub_add_cancel (h : t ≤ s) : s - t + t = s :=
id                                           
src                                              
typ                                          
1134  by rw [add_comm, add_sub_of_le h]
id          └──────┘  └───────────┘ 
src     └──┘└──────┘└┘└───────────┘ └─
typ     └──┘└──────┘└┘└───────────┘└─
doc     └──┘        └┘              └─
txt     └──┘        └┘              └─
par     └──┘        └┘              └─
pid       └┘        └┘              
st     └───────────┘└───────────────┘
1135  
src  
typ  
doc  
txt  
par  
pid  
st   
1136  @[simp] theorem add_sub_cancel_left (s : multiset α) : ∀ t, s + t - s = t :=
id                                            └──────┘               
src                                           └──────┘                   
typ                                           └──────┘               
doc    └──┘                                   └──────┘
1137  multiset.induction_on s (by simp)
id   └───────────────────┘ 
src  └───────────────────┘       └──┘
typ  └───────────────────┘      └──┘
doc                              └──┘
txt                              └──┘
par                              └──┘
st                              └───┘
1138    (λ a s IH t, by rw [cons_add, sub_cons, erase_cons_head, IH])
id          └┘          └──────┘  └──────┘  └─────────────┘  └┘
src                    └──┘└──────┘└┘└──────┘└┘└─────────────┘└┘  
typ         └┘      └──┘└──────┘└┘└──────┘└┘└─────────────┘└┘└┘
doc                    └──┘        └┘        └┘               └┘  
txt                    └──┘        └┘        └┘               └┘  
par                    └──┘        └┘        └┘               └┘  
pid                      └┘        └┘        └┘               └┘  
st                    └───────────┘└────────┘└───────────────┘└──┘
1139  
1140  @[simp] theorem add_sub_cancel (s t : multiset α) : s + t - t = s :=
id                                         └──────┘           
src                                        └──────┘              
typ                                        └──────┘           
doc    └──┘                                └──────┘
1141  by rw [add_comm, add_sub_cancel_left]
id          └──────┘  └─────────────────┘
src     └──┘└──────┘└┘└─────────────────┘└─
typ     └──┘└──────┘└┘└─────────────────┘└─
doc     └──┘        └┘                   └─
txt     └──┘        └┘                   └─
par     └──┘        └┘                   └─
pid       └┘        └┘                   
st     └───────────┘└───────────────────┘
1142  
src  
typ  
doc  
txt  
par  
pid  
st   
1143  theorem sub_le_sub_right (h : s ≤ t) (u) : s - u ≤ t - u :=
id                                                 
src                                                    
typ                                                
1144  by revert s t h; exact
src     └──────────┘  └────┘
typ     └──────────┘  └────┘
doc     └──────────┘  └────┘
txt     └──────────┘  └────┘
par     └──────────┘  └────┘
pid           └────┘       
st     └────────────────────
1145  multiset.induction_on u (by simp {contextual := tt})
id   └───────────────────┘                          └┘
src  └───────────────────┘    └───┘ └────────────┘└┘└─
typ  └───────────────────┘   └───┘ └────────────┘└┘└─
doc                           └───┘ └────────────┘  └─
txt                           └───┘ └────────────┘  └─
par                           └───┘ └────────────┘  └─
pid                           └────┘ └────────────┘  └──
st   ──────────────────────────┘└──────────────────────┘└─
1146    (λ a u IH s t h, by simp [IH, erase_le_erase a h])
id                                   └────────────┘  
src  ─┘  └─────────────┘  └────┘  └┘└────────────┘  └─
typ  ─┘  └─────────────┘  └────┘└┘└┘└────────────┘└─
doc  ─┘  └─────────────┘  └────┘  └┘                └─
txt  ─┘  └─────────────┘  └────┘  └┘                └─
par  ─┘  └─────────────┘  └────┘  └┘                └─
pid  ─┘  └─────────────┘  └─────┘  └┘                └┘
st   ────────────────────┘└────────────────────────────┘└─
1147  
src  
typ  
doc  
txt  
par  
pid  
st   
1148  theorem sub_le_sub_left (h : s ≤ t) : ∀ u, u - t ≤ u - s :=
id                                                
src                                                    
typ                                               
1149  le_induction_on h $ λ l₁ l₂ h, begin
id   └─────────────┘      └┘ └┘ 
src  └─────────────┘
typ  └─────────────┘      └┘ └┘ 
st                                  └─────
1150    induction h with l₁ l₂ a s IH l₁ l₂ a s IH; intro u,
id               
src    └────────┘ └─────────────────────────────┘  └─────┘
typ    └────────┘└─────────────────────────────┘  └─────┘
doc    └────────┘ └─────────────────────────────┘  └─────┘
txt    └────────┘ └─────────────────────────────┘  └─────┘
par    └────────┘ └─────────────────────────────┘  └─────┘
pid              └────────────────────────────┘       └┘
st   ────────────────────────────────────────────────────┘└─
1151    { refl },
src      └───┘
typ      └───┘
doc      └───┘
txt      └───┘
par      └───┘
pid          
st   ───┘└───┘└┘
1152    { rw [← cons_coe, sub_cons],
id             └──────┘  └──────┘
src      └────┘└──────┘└┘└──────┘
typ      └────┘└──────┘└┘└──────┘
doc      └────┘        └┘        
txt      └────┘        └┘        
par      └────┘        └┘        
pid        └──┘        └┘        
st   ───┘└────────────┘└────────┘└─
1153      exact le_trans (sub_le_sub_right (erase_le _ _) _) (IH u) },
id             └──────┘  └──────────────┘  └──────┘          └┘ 
src      └────┘└──────┘ └──────────────┘ └──────┘└───────┘    └┘
typ      └────┘└──────┘ └──────────────┘ └──────┘└───────┘ └┘└┘
doc      └────┘                                  └───────┘    └┘
txt      └────┘                                  └───────┘    └┘
par      └────┘                                  └───────┘    └┘
pid                                             └───────┘    
st   ─────────────────────────────────────────────────────────────┘└┘
1154    { rw [← cons_coe, sub_cons, ← cons_coe, sub_cons],
id             └──────┘  └──────┘    └──────┘  └──────┘
src      └────┘└──────┘└┘└──────┘└──┘└──────┘└┘└──────┘
typ      └────┘└──────┘└┘└──────┘└──┘└──────┘└┘└──────┘
doc      └────┘        └┘        └──┘        └┘        
txt      └────┘        └┘        └──┘        └┘        
par      └────┘        └┘        └──┘        └┘        
pid        └──┘        └┘        └──┘        └┘        
st   ─────────────────┘└────────┘└──────────┘└────────┘└─
1155      exact IH _ }
id             └┘
src      └────┘  └─┘
typ      └────┘└┘└─┘
doc      └────┘  └─┘
txt      └────┘  └─┘
par      └────┘  └─┘
pid             └┘
st   ──────────────┘└─
1156  end
st   ──┘
1157  
1158  theorem sub_le_iff_le_add : s - t ≤ u ↔ s ≤ u + t :=
id                                         
src                                            
typ                                        
1159  by revert s; exact
src     └──────┘  └────┘
typ     └──────┘  └────┘
doc     └──────┘  └────┘
txt     └──────┘  └────┘
par     └──────┘  └────┘
pid           └┘       
st     └────────────────
1160  multiset.induction_on t (by simp)
id   └───────────────────┘ 
src  └───────────────────┘    └──┘└─
typ  └───────────────────┘   └──┘└─
doc                           └──┘└─
txt                           └──┘└─
par                           └──┘└─
pid                           └──────
st   ──────────────────────────┘└───┘└─
1161    (λ a t IH s, by simp [IH, erase_le_iff_le_cons])
id                               └──────────────────┘
src  ─┘  └─────────┘  └────┘  └┘└──────────────────┘└─
typ  ─┘  └─────────┘  └────┘└┘└┘└──────────────────┘└─
doc  ─┘  └─────────┘  └────┘  └┘                    └─
txt  ─┘  └─────────┘  └────┘  └┘                    └─
par  ─┘  └─────────┘  └────┘  └┘                    └─
pid  ─┘  └─────────┘  └─────┘  └┘                    └┘
st   ────────────────┘└──────────────────────────────┘└─
1162  
src  
typ  
doc  
txt  
par  
pid  
st   
1163  theorem le_sub_add (s t : multiset α) : s ≤ s - t + t :=
id                             └──────┘           
src                            └──────┘              
typ                            └──────┘           
doc                            └──────┘
1164  sub_le_iff_le_add.1 (le_refl _)
id   └───────────────┘   └─────┘
src  └───────────────┘   └─────┘
typ  └───────────────┘   └─────┘
1165  
1166  theorem sub_le_self (s t : multiset α) : s - t ≤ s :=
id                              └──────┘         
src                             └──────┘           
typ                             └──────┘         
doc                             └──────┘
1167  sub_le_iff_le_add.2 (le_add_right _ _)
id   └───────────────┘   └──────────┘
src  └───────────────┘   └──────────┘
typ  └───────────────┘   └──────────┘
1168  
1169  @[simp] theorem card_sub {s t : multiset α} (h : t ≤ s) : card (s - t) = card s - card t :=
id                                   └──────┘              └──┘       └──┘   └──┘ 
src                                  └──────┘                 └──┘         └──┘    └──┘
typ                                  └──────┘              └──┘       └──┘   └──┘ 
doc    └──┘                          └──────┘                  └──┘           └──┘     └──┘
1170  (nat.sub_eq_of_eq_add $ by rw [add_comm, ← card_add, sub_add_cancel h]).symm
id    └──────────────────┘          └──────┘    └──────┘  └────────────┘   └──┘
src   └──────────────────┘      └──┘└──────┘└──┘└──────┘└┘└────────────┘  └──┘
typ   └──────────────────┘      └──┘└──────┘└──┘└──────┘└┘└────────────┘ └──┘
doc                             └──┘        └──┘        └┘               
txt                             └──┘        └──┘        └┘               
par                             └──┘        └──┘        └┘               
pid                               └┘        └──┘        └┘               
st                             └───────────┘└──────────┘└────────────────┘
1171  
1172  /- union -/
1173  
1174  /-- `s ∪ t` is the lattice join operation with respect to the
1175    multiset `≤`. The multiplicity of `a` in `s ∪ t` is the maximum
1176    of the multiplicities in `s` and `t`. -/
1177  def union (s t : multiset α) : multiset α := s - t + t
id                    └──────┘     └──────┘         
src                   └──────┘      └──────┘           
typ                   └──────┘     └──────┘         
doc                   └──────┘      └──────┘
1178  
1179  instance : has_union (multiset α) := ⟨union⟩
id              └───────┘  └──────┘       └───┘
src             └───────┘  └──────┘        └───┘
typ             └───────┘  └──────┘       └───┘
doc                        └──────┘        └───┘
1180  
1181  theorem union_def (s t : multiset α) : s ∪ t = s - t + t := rfl
id                            └──────┘                 └─┘
src                           └──────┘                       └─┘
typ                           └──────┘                 └─┘
doc                           └──────┘
1182  
1183  theorem le_union_left (s t : multiset α) : s ≤ s ∪ t := le_sub_add _ _
id                                └──────┘             └────────┘
src                               └──────┘                 └────────┘
typ                               └──────┘             └────────┘
doc                               └──────┘
1184  
1185  theorem le_union_right (s t : multiset α) : t ≤ s ∪ t := le_add_left _ _
id                                 └──────┘             └─────────┘
src                                └──────┘                 └─────────┘
typ                                └──────┘             └─────────┘
doc                                └──────┘
1186  
1187  theorem eq_union_left : t ≤ s → s ∪ t = s := sub_add_cancel
id                                        └────────────┘
src                                            └────────────┘
typ                                       └────────────┘
1188  
1189  theorem union_le_union_right (h : s ≤ t) (u) : s ∪ u ≤ t ∪ u :=
id                                                     
src                                                        
typ                                                    
1190  add_le_add_right (sub_le_sub_right h _) u
id   └──────────────┘  └──────────────┘     
src  └──────────────┘  └──────────────┘
typ  └──────────────┘  └──────────────┘     
1191  
1192  theorem union_le (h₁ : s ≤ u) (h₂ : t ≤ u) : s ∪ t ≤ u :=
id                                              
src                                                  
typ                                             
1193  by rw ← eq_union_left h₂; exact union_le_union_right h₁ t
id           └───────────┘ └┘        └──────────────────┘ └┘ 
src     └───┘└───────────┘    └────┘└──────────────────┘   
typ     └───┘└───────────┘└┘  └────┘└──────────────────┘└┘
doc     └───┘                 └────┘                       
txt     └───┘                 └────┘                       
par     └───┘                 └────┘                       
pid       └─┘                                             
st     └───────────────────────────────────────────────────────
1194  
src  
typ  
doc  
txt  
par  
pid  
st   
1195  @[simp] theorem mem_union : a ∈ s ∪ t ↔ a ∈ s ∨ a ∈ t :=
id                                           
src                                               
typ                                          
doc    └──┘
1196  ⟨λ h, (mem_add.1 h).imp_left (mem_of_le $ sub_le_self _ _),
id         └─────┘   └──────┘   └───────┘   └─────────┘
src         └─────┘    └──────┘   └───────┘   └─────────┘
typ        └─────┘   └──────┘   └───────┘   └─────────┘
1197   or.rec (mem_of_le $ le_union_left _ _) (mem_of_le $ le_union_right _ _)⟩
id    └────┘  └───────┘   └───────────┘       └───────┘   └────────────┘
src   └────┘  └───────┘   └───────────┘       └───────┘   └────────────┘
typ   └────┘  └───────┘   └───────────┘       └───────┘   └────────────┘
1198  
1199  @[simp] theorem map_union [decidable_eq β] {f : α → β} (finj : function.injective f) {s t : multiset α} :
id                              └──────────┘                     └────────────────┘          └──────┘ 
src                             └──────────┘                        └────────────────┘           └──────┘
typ                             └──────────┘                     └────────────────┘          └──────┘ 
doc    └──┘                                                                                      └──────┘
1200    map f (s ∪ t) = map f s ∪ map f t :=
id     └─┘        └─┘    └─┘  
src    └─┘           └─┘      └─┘
typ    └─┘        └─┘    └─┘  
doc    └─┘             └─┘       └─┘
1201  quotient.induction_on₂ s t $ λ l₁ l₂,
id   └────────────────────┘       └┘ └┘
src  └────────────────────┘
typ  └────────────────────┘       └┘ └┘
1202  congr_arg coe (by rw [list.map_append f, list.map_diff finj])
id   └───────┘ └─┘         └─────────────┘   └───────────┘ └──┘
src  └───────┘ └─┘     └──┘└─────────────┘ └┘└───────────┘    
typ  └───────┘ └─┘     └──┘└─────────────┘└┘└───────────┘└──┘
doc                    └──┘                └┘                 
txt                    └──┘                └┘                 
par                    └──┘                └┘                 
pid                      └┘                └┘                 
st                    └────────────────────┘└──────────────────┘
1203  
1204  /- inter -/
1205  
1206  /-- `s ∩ t` is the lattice meet operation with respect to the
1207    multiset `≤`. The multiplicity of `a` in `s ∩ t` is the minimum
1208    of the multiplicities in `s` and `t`. -/
1209  def inter (s t : multiset α) : multiset α :=
id                    └──────┘     └──────┘ 
src                   └──────┘      └──────┘
typ                   └──────┘     └──────┘ 
doc                   └──────┘      └──────┘
1210  quotient.lift_on₂ s t (λ l₁ l₂, (l₁.bag_inter l₂ : multiset α)) $ λ v₁ v₂ w₁ w₂ p₁ p₂,
id   └───────────────┘      └┘ └┘   └┘└────────┘ └┘   └──────┘        └┘ └┘ └┘ └┘ └┘ └┘
src  └───────────────┘                  └────────┘      └──────┘
typ  └───────────────┘      └┘ └┘   └┘└────────┘ └┘   └──────┘        └┘ └┘ └┘ └┘ └┘ └┘
doc                                                     └──────┘
1211    quot.sound $ perm_bag_inter_right w₁ p₂ ▸ perm_bag_inter_left _ p₁
id     └────────┘   └──────────────────┘ └┘ └┘  └─────────────────┘   └┘
src    └────────┘   └──────────────────┘        └─────────────────┘
typ    └────────┘   └──────────────────┘ └┘ └┘  └─────────────────┘   └┘
1212  
1213  instance : has_inter (multiset α) := ⟨inter⟩
id              └───────┘  └──────┘       └───┘
src             └───────┘  └──────┘        └───┘
typ             └───────┘  └──────┘       └───┘
doc                        └──────┘        └───┘
1214  
1215  @[simp] theorem inter_zero (s : multiset α) : s ∩ 0 = 0 :=
id                                   └──────┘         
src                                  └──────┘           
typ                                  └──────┘         
doc    └──┘                          └──────┘
1216  quot.induction_on s $ λ l, congr_arg coe l.bag_inter_nil
id   └───────────────┘        └───────┘ └─┘ └────────────┘
src  └───────────────┘          └───────┘ └─┘  └────────────┘
typ  └───────────────┘        └───────┘ └─┘ └────────────┘
1217  
1218  @[simp] theorem zero_inter (s : multiset α) : 0 ∩ s = 0 :=
id                                   └──────┘         
src                                  └──────┘           
typ                                  └──────┘         
doc    └──┘                          └──────┘
1219  quot.induction_on s $ λ l, congr_arg coe l.nil_bag_inter
id   └───────────────┘        └───────┘ └─┘ └────────────┘
src  └───────────────┘          └───────┘ └─┘  └────────────┘
typ  └───────────────┘        └───────┘ └─┘ └────────────┘
1220  
1221  @[simp] theorem cons_inter_of_pos {a} (s : multiset α) {t} :
id                                              └──────┘ 
src                                             └──────┘
typ                                             └──────┘ 
doc    └──┘                                     └──────┘
1222    a ∈ t → (a :: s) ∩ t = a :: s ∩ t.erase a :=
id            └┘       └┘   └────┘ 
src              └┘          └┘     └────┘
typ           └┘       └┘   └────┘ 
doc               └┘            └┘      └────┘
1223  quotient.induction_on₂ s t $ λ l₁ l₂ h,
id   └────────────────────┘       └┘ └┘ 
src  └────────────────────┘
typ  └────────────────────┘       └┘ └┘ 
1224  congr_arg coe $ cons_bag_inter_of_pos _ h
id   └───────┘ └─┘   └───────────────────┘   
src  └───────┘ └─┘   └───────────────────┘
typ  └───────┘ └─┘   └───────────────────┘   
1225  
1226  @[simp] theorem cons_inter_of_neg {a} (s : multiset α) {t} :
id                                              └──────┘ 
src                                             └──────┘
typ                                             └──────┘ 
doc    └──┘                                     └──────┘
1227    a ∉ t → (a :: s) ∩ t = s ∩ t :=
id            └┘        
src              └┘          
typ           └┘        
doc               └┘
1228  quotient.induction_on₂ s t $ λ l₁ l₂ h,
id   └────────────────────┘       └┘ └┘ 
src  └────────────────────┘
typ  └────────────────────┘       └┘ └┘ 
1229  congr_arg coe $ cons_bag_inter_of_neg _ h
id   └───────┘ └─┘   └───────────────────┘   
src  └───────┘ └─┘   └───────────────────┘
typ  └───────┘ └─┘   └───────────────────┘   
1230  
1231  theorem inter_le_left (s t : multiset α) : s ∩ t ≤ s :=
id                                └──────┘         
src                               └──────┘           
typ                               └──────┘         
doc                               └──────┘
1232  quotient.induction_on₂ s t $ λ l₁ l₂,
id   └────────────────────┘       └┘ └┘
src  └────────────────────┘
typ  └────────────────────┘       └┘ └┘
1233  subperm_of_sublist $ bag_inter_sublist_left _ _
id   └────────────────┘   └────────────────────┘
src  └────────────────┘   └────────────────────┘
typ  └────────────────┘   └────────────────────┘
1234  
1235  theorem inter_le_right (s : multiset α) : ∀ t, s ∩ t ≤ t :=
id                               └──────┘             
src                              └──────┘                
typ                              └──────┘             
doc                              └──────┘
1236  multiset.induction_on s (λ t, (zero_inter t).symm ▸ zero_le _) $
id   └───────────────────┘        └────────┘  └──┘   └─────┘
src  └───────────────────┘          └────────┘   └──┘   └─────┘
typ  └───────────────────┘        └────────┘  └──┘   └─────┘
1237  λ a s IH t, if h : a ∈ t
id       └┘   └┘       
src              └┘       
typ      └┘   └┘       
1238    then by simpa [h] using cons_le_cons a (IH (t.erase a))
id                            └──────────┘    └┘  └─────┘ 
src            └─────┘ └──────┘└──────────┘     └─────┘ └──
typ            └─────┘└──────┘└──────────┘  └┘ └─────┘└──
doc            └─────┘ └──────┘                 └─────┘ └──
txt            └─────┘ └──────┘                         └──
par            └─────┘ └──────┘                         └──
pid                  └────┘                         └┘
st            └────────────────────────────────────────────────
1239    else by simp [h, IH]
id                     └┘
src  ─┘        └────┘ └┘  └─
typ  ─┘        └────┘└┘└┘└─
doc  ─┘        └────┘ └┘  └─
txt  ─┘        └────┘ └┘  └─
par  ─┘        └────┘ └┘  └─
pid  ─┘             └┘  
st   ─┘       └─────────────
1240  
src  
typ  
doc  
txt  
par  
pid  
st   
1241  theorem le_inter (h₁ : s ≤ t) (h₂ : s ≤ u) : s ≤ t ∩ u :=
id                                              
src                                                  
typ                                             
1242  begin
st   └─────
1243    revert s u, refine multiset.induction_on t _ (λ a t IH, _); intros,
id                        └───────────────────┘ 
src    └────────┘  └─────┘└───────────────────┘ └─┘  └─────────┘  └────┘
typ    └────────┘  └─────┘└───────────────────┘└─┘  └─────────┘  └────┘
doc    └────────┘  └─────┘                      └─┘  └─────────┘  └────┘
txt    └────────┘  └─────┘                      └─┘  └─────────┘  └────┘
par    └────────┘  └─────┘                      └─┘  └─────────┘  └────┘
pid          └──┘                              └─┘  └─────────┘
st   ───────────┘└──────────────────────────────────────────────────────┘└─
1244    { simp [h₁] },
id             └┘
src      └────┘  └┘
typ      └────┘└┘└┘
doc      └────┘  └┘
txt      └────┘  └┘
par      └────┘  └┘
pid            
st   ───┘└────────┘└┘
1245    by_cases a ∈ u,
id                
src    └───────┘ 
typ    └───────┘
doc    └───────┘  
txt    └───────┘  
par    └───────┘  
pid              
st   ───────────────┘└─
1246    { rw [cons_inter_of_pos _ h, ← erase_le_iff_le_cons],
id           └───────────────┘       └──────────────────┘
src      └──┘└───────────────┘└─┘ └──┘└──────────────────┘
typ      └──┘└───────────────┘└─┘└──┘└──────────────────┘
doc      └──┘                 └─┘ └──┘                    
txt      └──┘                 └─┘ └──┘                    
par      └──┘                 └─┘ └──┘                    
pid        └┘                 └─┘ └──┘                    
st   ───┘└───────────────────────┘└──────────────────────┘└──
1247      exact IH (erase_le_iff_le_cons.2 h₁) (erase_le_erase _ h₂) },
id             └┘  └──────────────────┘   └┘   └────────────┘   └┘
src      └────┘   └──────────────────┘└─┘  └┘ └────────────┘└─┘  └┘
typ      └────┘└┘ └──────────────────┘└─┘└┘└┘ └────────────┘└─┘└┘└┘
doc      └────┘                       └─┘  └┘               └─┘  └┘
txt      └────┘                       └─┘  └┘               └─┘  └┘
par      └────┘                       └─┘  └┘               └─┘  └┘
pid                                  └─┘  └┘               └─┘  
st   ──────────────────────────────────────────────────────────────┘└┘
1248    { rw cons_inter_of_neg _ h,
id          └───────────────┘   
src      └─┘└───────────────┘└─┘
typ      └─┘└───────────────┘└─┘
doc      └─┘                 └─┘
txt      └─┘                 └─┘
par      └─┘                 └─┘
pid                         └─┘
st   ───────────────────────────┘└─
1249      exact IH ((le_cons_of_not_mem $ mt (mem_of_le h₂) h).1 h₁) h₂ }
id             └┘   └────────────────┘   └┘  └───────┘         └┘  └┘
src      └────┘    └────────────────┘ └┘ └───────┘  └┘ └──┘  └┘  
typ      └────┘└┘  └────────────────┘ └┘ └───────┘  └┘└──┘└┘└┘└┘
doc      └────┘                                     └┘ └──┘  └┘  
txt      └────┘                                     └┘ └──┘  └┘  
par      └────┘                                     └┘ └──┘  └┘  
pid                                                └┘ └──┘  └┘  
st   ─────────────────────────────────────────────────────────────────┘└─
1250  end
st   ──┘
1251  
1252  @[simp] theorem mem_inter : a ∈ s ∩ t ↔ a ∈ s ∧ a ∈ t :=
id                                           
src                                               
typ                                          
doc    └──┘
1253  ⟨λ h, ⟨mem_of_le (inter_le_left _ _) h, mem_of_le (inter_le_right _ _) h⟩,
id         └───────┘  └───────────┘        └───────┘  └────────────┘      
src         └───────┘  └───────────┘         └───────┘  └────────────┘
typ        └───────┘  └───────────┘        └───────┘  └────────────┘      
1254   λ ⟨h₁, h₂⟩, by rw [← cons_erase h₁, cons_inter_of_pos _ h₂]; apply mem_cons_self⟩
id                        └────────┘ └┘  └───────────────┘   └┘         └───────────┘
src                  └────┘└────────┘  └┘└───────────────┘└─┘    └────┘└───────────┘
typ                 └────┘└────────┘└┘└┘└───────────────┘└─┘└┘  └────┘└───────────┘
doc                  └────┘            └┘                 └─┘    └────┘
txt                  └────┘            └┘                 └─┘    └────┘
par                  └────┘            └┘                 └─┘    └────┘
pid                    └──┘            └┘                 └─┘         
st                  └──────────────────┘└──────────────────────┘└───────────────────┘
1255  
1256  instance : lattice (multiset α) :=
id              └─────┘  └──────┘ 
src             └─────┘  └──────┘
typ             └─────┘  └──────┘ 
doc             └─────┘  └──────┘
1257  { sup          := (∪),
id                     
src                    
typ                    
1258    sup_le       := @union_le _ _,
id                      └──────┘
src                     └──────┘
typ                     └──────┘
1259    le_sup_left  := le_union_left,
id                     └───────────┘
src                    └───────────┘
typ                    └───────────┘
1260    le_sup_right := le_union_right,
id                     └────────────┘
src                    └────────────┘
typ                    └────────────┘
1261    inf          := (∩),
id                     
src                    
typ                    
1262    le_inf       := @le_inter _ _,
id                      └──────┘
src                     └──────┘
typ                     └──────┘
1263    inf_le_left  := inter_le_left,
id                     └───────────┘
src                    └───────────┘
typ                    └───────────┘
1264    inf_le_right := inter_le_right,
id                     └────────────┘
src                    └────────────┘
typ                    └────────────┘
1265    ..@multiset.partial_order α }
id        └────────────────────┘ 
src       └────────────────────┘
typ       └────────────────────┘ 
1266  
1267  @[simp] theorem sup_eq_union (s t : multiset α) : s ⊔ t = s ∪ t := rfl
id                                       └──────┘               └─┘
src                                      └──────┘                    └─┘
typ                                      └──────┘               └─┘
doc    └──┘                              └──────┘
1268  @[simp] theorem inf_eq_inter (s t : multiset α) : s ⊓ t = s ∩ t := rfl
id                                       └──────┘               └─┘
src                                      └──────┘                    └─┘
typ                                      └──────┘               └─┘
doc    └──┘                              └──────┘
1269  
1270  @[simp] theorem le_inter_iff : s ≤ t ∩ u ↔ s ≤ t ∧ s ≤ u := le_inf_iff
id                                                  └────────┘
src                                                        └────────┘
typ                                                 └────────┘
doc    └──┘
1271  @[simp] theorem union_le_iff : s ∪ t ≤ u ↔ s ≤ u ∧ t ≤ u := sup_le_iff
id                                                  └────────┘
src                                                        └────────┘
typ                                                 └────────┘
doc    └──┘
1272  
1273  instance : semilattice_inf_bot (multiset α) :=
id              └─────────────────┘  └──────┘ 
src             └─────────────────┘  └──────┘
typ             └─────────────────┘  └──────┘ 
doc             └─────────────────┘  └──────┘
1274  { bot := 0, bot_le := zero_le, ..multiset.lattice.lattice }
id                         └─────┘    └──────────────────────┘
src                        └─────┘    └──────────────────────┘
typ                        └─────┘    └──────────────────────┘
1275  
1276  theorem union_comm (s t : multiset α) : s ∪ t = t ∪ s := sup_comm
id                             └──────┘               └──────┘
src                            └──────┘                    └──────┘
typ                            └──────┘               └──────┘
doc                            └──────┘
1277  theorem inter_comm (s t : multiset α) : s ∩ t = t ∩ s := inf_comm
id                             └──────┘               └──────┘
src                            └──────┘                    └──────┘
typ                            └──────┘               └──────┘
doc                            └──────┘
1278  
1279  theorem eq_union_right (h : s ≤ t) : s ∪ t = t :=
id                                         
src                                           
typ                                        
1280  by rw [union_comm, eq_union_left h]
id          └────────┘  └───────────┘ 
src     └──┘└────────┘└┘└───────────┘ └─
typ     └──┘└────────┘└┘└───────────┘└─
doc     └──┘          └┘              └─
txt     └──┘          └┘              └─
par     └──┘          └┘              └─
pid       └┘          └┘              
st     └─────────────┘└───────────────┘
1281  
src  
typ  
doc  
txt  
par  
pid  
st   
1282  theorem union_le_union_left (h : s ≤ t) (u) : u ∪ s ≤ u ∪ t :=
id                                                    
src                                                       
typ                                                   
1283  sup_le_sup_left h _
id   └─────────────┘ 
src  └─────────────┘
typ  └─────────────┘ 
1284  
1285  theorem union_le_add (s t : multiset α) : s ∪ t ≤ s + t :=
id                               └──────┘           
src                              └──────┘              
typ                              └──────┘           
doc                              └──────┘
1286  union_le (le_add_right _ _) (le_add_left _ _)
id   └──────┘  └──────────┘       └─────────┘
src  └──────┘  └──────────┘       └─────────┘
typ  └──────┘  └──────────┘       └─────────┘
1287  
1288  theorem union_add_distrib (s t u : multiset α) : (s ∪ t) + u = (s + u) ∪ (t + u) :=
id                                      └──────┘                      
src                                     └──────┘                            
typ                                     └──────┘                      
doc                                     └──────┘
1289  by simpa [(∪), union, eq_comm] using show s + u - (t + u) = s - t,
id                  └───┘  └─────┘                              
src     └─────┘ └──┘└───┘└┘└─────┘└──────┘          └┘   └─
typ     └─────┘ └──┘└───┘└┘└─────┘└──────┘         └┘ └─
doc     └─────┘ └──┘└───┘└┘       └──────┘            └┘    └─
txt     └─────┘ └──┘     └┘       └──────┘            └┘    └─
par     └─────┘ └──┘     └┘       └──────┘            └┘    └─
pid           └──┘     └┘       └────┘            └┘    └─
st     └────────────────────────────────────────────────────────────────
1290  by rw [add_comm t, sub_add', add_sub_cancel]
id          └──────┘   └──────┘  └────────────┘
src  ──┘└──┘└──────┘ └┘└──────┘└┘└────────────┘└─
typ  ──┘└──┘└──────┘└┘└──────┘└┘└────────────┘└─
doc  ──┘└──┘         └┘        └┘              └─
txt  ──┘└──┘         └┘        └┘              └─
par  ──┘└──┘         └┘        └┘              └─
pid  ──────┘         └┘        └┘              └─
st   ─┘└─────────────┘└────────┘└──────────────┘
1291  
src  
typ  
doc  
txt  
par  
pid  
st   
1292  theorem add_union_distrib (s t u : multiset α) : s + (t ∪ u) = (s + t) ∪ (s + u) :=
id                                      └──────┘                      
src                                     └──────┘                            
typ                                     └──────┘                      
doc                                     └──────┘
1293  by rw [add_comm, union_add_distrib, add_comm s, add_comm s]
id          └──────┘  └───────────────┘  └──────┘   └──────┘ 
src     └──┘└──────┘└┘└───────────────┘└┘└──────┘ └┘└──────┘ └─
typ     └──┘└──────┘└┘└───────────────┘└┘└──────┘└┘└──────┘└─
doc     └──┘        └┘                 └┘         └┘         └─
txt     └──┘        └┘                 └┘         └┘         └─
par     └──┘        └┘                 └┘         └┘         └─
pid       └┘        └┘                 └┘         └┘         
st     └───────────┘└─────────────────┘└──────────┘└──────────┘
1294  
src  
typ  
doc  
txt  
par  
pid  
st   
1295  theorem cons_union_distrib (a : α) (s t : multiset α) : a :: (s ∪ t) = (a :: s) ∪ (a :: t) :=
id                                            └──────┘      └┘         └┘      └┘ 
src                                            └──────┘        └┘            └┘        └┘
typ                                           └──────┘      └┘         └┘      └┘ 
doc                                            └──────┘        └┘              └┘         └┘
1296  by simpa using add_union_distrib (a::0) s t
id                  └───────────────┘  └┘    
src     └──────────┘└───────────────┘  └┘└─┘  
typ     └──────────┘└───────────────┘ └┘└─┘
doc     └──────────┘                   └┘└─┘  
txt     └──────────┘                     └─┘  
par     └──────────┘                     └─┘  
pid          └────┘                     └─┘  
st     └─────────────────────────────────────────
1297  
src  
typ  
doc  
txt  
par  
pid  
st   
1298  theorem inter_add_distrib (s t u : multiset α) : (s ∩ t) + u = (s + u) ∩ (t + u) :=
id                                      └──────┘                      
src                                     └──────┘                            
typ                                     └──────┘                      
doc                                     └──────┘
1299  begin
st   └─────
1300    by_contra h,
src    └─────────┘
typ    └─────────┘
doc    └─────────┘
txt    └─────────┘
par    └─────────┘
pid             └┘
st   ────────────┘└─
1301    cases lt_iff_cons_le.1 (lt_of_le_of_ne (le_inter
id           └────────────┘    └────────────┘  └──────┘
src    └────┘└────────────┘└─┘ └────────────┘ └──────┘
typ    └────┘└────────────┘└─┘ └────────────┘ └──────┘
doc    └────┘              └─┘                        
txt    └────┘              └─┘                        
par    └────┘              └─┘                        
pid                       └─┘                        
st   ───────────────────────────────────────────────────
1302      (add_le_add_right (inter_le_left s t) u)
id                          └───────────┘
src  ───┘                  └───────────┘  └┘ └─
typ  ───┘                  └───────────┘  └┘ └─
doc  ───┘                                 └┘ └─
txt  ───┘                                 └┘ └─
par  ───┘                                 └┘ └─
pid  ───┘                                 └┘ └─
st   ─────────────────────────────────────────────
1303      (add_le_add_right (inter_le_right s t) u)) h) with a hl,
id        └──────────────┘  └────────────┘       
src  ───┘ └──────────────┘ └────────────┘  └┘ └─┘ └─────────┘
typ  ───┘ └──────────────┘ └────────────┘└┘└─┘└─────────┘
doc  ───┘                                  └┘ └─┘ └─────────┘
txt  ───┘                                  └┘ └─┘ └─────────┘
par  ───┘                                  └┘ └─┘ └─────────┘
pid  ───┘                                  └┘ └─┘ └────────┘
st   ──────────────────────────────────────────────────────────┘└─
1304    rw ← cons_add at hl,
id          └──────┘
src    └───┘└──────┘└────┘
typ    └───┘└──────┘└────┘
doc    └───┘        └────┘
txt    └───┘        └────┘
par    └───┘        └────┘
pid      └─┘        └────┘
st   ────────────────────┘└─
1305    exact not_le_of_lt (lt_cons_self (s ∩ t) a) (le_inter
id           └──────────┘  └──────────┘         └──────┘
src    └────┘└──────────┘ └──────────┘   └┘ └┘ └──────┘
typ    └────┘└──────────┘ └──────────┘ └┘└┘ └──────┘
doc    └────┘                             └┘ └┘         
txt    └────┘                             └┘ └┘         
par    └────┘                             └┘ └┘         
pid                                      └┘ └┘         
st   ────────────────────────────────────────────────────────
1306      (le_of_add_le_add_right (le_trans hl (inter_le_left _ _)))
id                                             └───────────┘
src  ───┘                                   └───────────┘└───────
typ  ───┘                                   └───────────┘└───────
doc  ───┘                                                └───────
txt  ───┘                                                └───────
par  ───┘                                                └───────
pid  ───┘                                                └───────
st   ───────────────────────────────────────────────────────────────
1307      (le_of_add_le_add_right (le_trans hl (inter_le_right _ _))))
id        └────────────────────┘  └──────┘ └┘  └────────────┘
src  ───┘ └────────────────────┘ └──────┘   └────────────┘└───────┘
typ  ───┘ └────────────────────┘ └──────┘└┘ └────────────┘└───────┘
doc  ───┘                                                 └───────┘
txt  ───┘                                                 └───────┘
par  ───┘                                                 └───────┘
pid  ───┘                                                 └──────┘
st   ────────────────────────────────────────────────────────────────┘
1308  end
st   └─┘
1309  
1310  theorem add_inter_distrib (s t u : multiset α) : s + (t ∩ u) = (s + t) ∩ (s + u) :=
id                                      └──────┘                      
src                                     └──────┘                            
typ                                     └──────┘                      
doc                                     └──────┘
1311  by rw [add_comm, inter_add_distrib, add_comm s, add_comm s]
id          └──────┘  └───────────────┘  └──────┘   └──────┘ 
src     └──┘└──────┘└┘└───────────────┘└┘└──────┘ └┘└──────┘ └─
typ     └──┘└──────┘└┘└───────────────┘└┘└──────┘└┘└──────┘└─
doc     └──┘        └┘                 └┘         └┘         └─
txt     └──┘        └┘                 └┘         └┘         └─
par     └──┘        └┘                 └┘         └┘         └─
pid       └┘        └┘                 └┘         └┘         
st     └───────────┘└─────────────────┘└──────────┘└──────────┘
1312  
src  
typ  
doc  
txt  
par  
pid  
st   
1313  theorem cons_inter_distrib (a : α) (s t : multiset α) : a :: (s ∩ t) = (a :: s) ∩ (a :: t) :=
id                                            └──────┘      └┘         └┘      └┘ 
src                                            └──────┘        └┘            └┘        └┘
typ                                           └──────┘      └┘         └┘      └┘ 
doc                                            └──────┘        └┘              └┘         └┘
1314  by simp
src     └────
typ     └────
doc     └────
txt     └────
par     └────
pid         
st     └─────
1315  
src  
typ  
doc  
txt  
par  
pid  
st   
1316  theorem union_add_inter (s t : multiset α) : s ∪ t + s ∩ t = s + t :=
id                                  └──────┘               
src                                 └──────┘                    
typ                                 └──────┘               
doc                                 └──────┘
1317  begin
st   └─────
1318    apply le_antisymm,
id           └─────────┘
src    └────┘└─────────┘
typ    └────┘└─────────┘
doc    └────┘
txt    └────┘
par    └────┘
pid         
st   ──────────────────┘└─
1319    { rw union_add_distrib,
id          └───────────────┘
src      └─┘└───────────────┘
typ      └─┘└───────────────┘
doc      └─┘
txt      └─┘
par      └─┘
pid        
st   ───┘└──────────────────┘└─
1320      refine union_le (add_le_add_left (inter_le_right _ _) _) _,
id              └──────┘  └─────────────┘  └────────────┘
src      └─────┘└──────┘ └─────────────┘ └────────────┘└────────┘
typ      └─────┘└──────┘ └─────────────┘ └────────────┘└────────┘
doc      └─────┘                                       └────────┘
txt      └─────┘                                       └────────┘
par      └─────┘                                       └────────┘
pid                                                   └────────┘
st   ─────────────────────────────────────────────────────────────┘└─
1321      rw add_comm, exact add_le_add_right (inter_le_left _ _) _ },
id          └──────┘        └──────────────┘  └───────────┘
src      └─┘└──────┘  └────┘└──────────────┘ └───────────┘└──────┘
typ      └─┘└──────┘  └────┘└──────────────┘ └───────────┘└──────┘
doc      └─┘          └────┘                              └──────┘
txt      └─┘          └────┘                              └──────┘
par      └─┘          └────┘                              └──────┘
pid                                                     └─────┘
st   ──────────────┘└─────────────────────────────────────────────┘└┘
1322    { rw [add_comm, add_inter_distrib],
id           └──────┘  └───────────────┘
src      └──┘└──────┘└┘└───────────────┘
typ      └──┘└──────┘└┘└───────────────┘
doc      └──┘        └┘                 
txt      └──┘        └┘                 
par      └──┘        └┘                 
pid        └┘        └┘                 
st   ───────────────┘└─────────────────┘└──
1323      refine le_inter (add_le_add_right (le_union_right _ _) _) _,
id              └──────┘  └──────────────┘  └────────────┘
src      └─────┘└──────┘ └──────────────┘ └────────────┘└────────┘
typ      └─────┘└──────┘ └──────────────┘ └────────────┘└────────┘
doc      └─────┘                                        └────────┘
txt      └─────┘                                        └────────┘
par      └─────┘                                        └────────┘
pid                                                    └────────┘
st   ──────────────────────────────────────────────────────────────┘└─
1324      rw add_comm, exact add_le_add_right (le_union_left _ _) _ }
id          └──────┘        └──────────────┘  └───────────┘
src      └─┘└──────┘  └────┘└──────────────┘ └───────────┘└──────┘
typ      └─┘└──────┘  └────┘└──────────────┘ └───────────┘└──────┘
doc      └─┘          └────┘                              └──────┘
txt      └─┘          └────┘                              └──────┘
par      └─┘          └────┘                              └──────┘
pid                                                     └─────┘
st   ──────────────┘└─────────────────────────────────────────────┘└─
1325  end
st   ──┘
1326  
1327  theorem sub_add_inter (s t : multiset α) : s - t + s ∩ t = s :=
id                                └──────┘             
src                               └──────┘                 
typ                               └──────┘             
doc                               └──────┘
1328  begin
st   └─────
1329    rw [inter_comm],
id         └────────┘
src    └──┘└────────┘
typ    └──┘└────────┘
doc    └──┘          
txt    └──┘          
par    └──┘          
pid      └┘          
st   ───────────────┘└──
1330    revert s, refine multiset.induction_on t (by simp) (λ a t IH s, _),
id                      └───────────────────┘ 
src    └──────┘  └─────┘└───────────────────┘    └──┘└┘  └───────────┘
typ    └──────┘  └─────┘└───────────────────┘   └──┘└┘  └───────────┘
doc    └──────┘  └─────┘                         └──┘└┘  └───────────┘
txt    └──────┘  └─────┘                         └──┘└┘  └───────────┘
par    └──────┘  └─────┘                         └──┘└┘  └───────────┘
pid          └┘                                 └─────┘  └───────────┘
st   ─────────┘└──────────────────────────────────┘└───┘└───────────────┘└─
1331    by_cases a ∈ s,
id                
src    └───────┘ 
typ    └───────┘
doc    └───────┘  
txt    └───────┘  
par    └───────┘  
pid              
st   ───────────────┘└─
1332    { rw [cons_inter_of_pos _ h, sub_cons, add_cons, IH, cons_erase h] },
id           └───────────────┘     └──────┘  └──────┘  └┘  └────────┘ 
src      └──┘└───────────────┘└─┘ └┘└──────┘└┘└──────┘└┘  └┘└────────┘ └┘
typ      └──┘└───────────────┘└─┘└┘└──────┘└┘└──────┘└┘└┘└┘└────────┘└┘
doc      └──┘                 └─┘ └┘        └┘        └┘  └┘           └┘
txt      └──┘                 └─┘ └┘        └┘        └┘  └┘           └┘
par      └──┘                 └─┘ └┘        └┘        └┘  └┘           └┘
pid        └┘                 └─┘ └┘        └┘        └┘  └┘           
st   ───┘└───────────────────────┘└────────┘└────────┘└──┘└────────────┘└┘
1333    { rw [cons_inter_of_neg _ h, sub_cons, erase_of_not_mem h, IH] }
id           └───────────────┘     └──────┘  └──────────────┘   └┘
src      └──┘└───────────────┘└─┘ └┘└──────┘└┘└──────────────┘ └┘  └┘
typ      └──┘└───────────────┘└─┘└┘└──────┘└┘└──────────────┘└┘└┘└┘
doc      └──┘                 └─┘ └┘        └┘                 └┘  └┘
txt      └──┘                 └─┘ └┘        └┘                 └┘  └┘
par      └──┘                 └─┘ └┘        └┘                 └┘  └┘
pid        └┘                 └─┘ └┘        └┘                 └┘  
st   ────────────────────────────┘└────────┘└──────────────────┘└──┘└─
1334  end
st   ──┘
1335  
1336  theorem sub_inter (s t : multiset α) : s - (s ∩ t) = s - t :=
id                            └──────┘               
src                           └──────┘                   
typ                           └──────┘               
doc                           └──────┘
1337  add_right_cancel $
id   └──────────────┘
src  └──────────────┘
typ  └──────────────┘
1338  by rw [sub_add_inter s t, sub_add_cancel (inter_le_left _ _)]
id          └───────────┘    └────────────┘  └───────────┘
src     └──┘└───────────┘  └┘└────────────┘ └───────────┘└──────
typ     └──┘└───────────┘└┘└────────────┘ └───────────┘└──────
doc     └──┘               └┘                            └──────
txt     └──┘               └┘                            └──────
par     └──┘               └┘                            └──────
pid       └┘               └┘                            └────┘
st     └────────────────────┘└──────────────────────────────────┘
1339  
src  
typ  
doc  
txt  
par  
pid  
st   
1340  end
1341  
1342  
1343  /- filter -/
1344  section
1345  variables {p : α → Prop} [decidable_pred p]
id                             └────────────┘
src                            └────────────┘
typ                            └────────────┘
1346  
1347  /-- `filter p s` returns the elements in `s` (with the same multiplicities)
1348    which satisfy `p`, and removes the rest. -/
1349  def filter (p : α → Prop) [h : decidable_pred p] (s : multiset α) : multiset α :=
id                                 └────────────┘        └──────┘     └──────┘ 
src                                 └────────────┘         └──────┘      └──────┘
typ                                └────────────┘        └──────┘     └──────┘ 
doc                                                        └──────┘      └──────┘
1350  quot.lift_on s (λ l, (filter p l : multiset α))
id   └──────────┘        └────┘     └──────┘ 
src  └──────────┘          └────┘       └──────┘
typ  └──────────┘        └────┘     └──────┘ 
doc                                     └──────┘
1351    (λ l₁ l₂ h, quot.sound $ perm_filter p h)
id        └┘ └┘   └────────┘   └─────────┘  
src                └────────┘   └─────────┘
typ       └┘ └┘   └────────┘   └─────────┘  
1352  
1353  @[simp] theorem coe_filter (p : α → Prop) [h : decidable_pred p]
id                                                 └────────────┘ 
src                                                 └────────────┘
typ                                                └────────────┘ 
doc    └──┘
1354    (l : list α) : filter p (↑l) = l.filter p := rfl
id          └──┘     └────┘      └─────┘     └─┘
src         └──┘      └────┘         └─────┘      └─┘
typ         └──┘     └────┘      └─────┘     └─┘
doc                   └────┘
1355  
1356  @[simp] theorem filter_zero (p : α → Prop) [h : decidable_pred p] : filter p 0 = 0 := rfl
id                                                  └────────────┘     └────┘          └─┘
src                                                  └────────────┘      └────┘           └─┘
typ                                                 └────────────┘     └────┘          └─┘
doc    └──┘                                                              └────┘
1357  
1358  @[simp] theorem filter_cons_of_pos {a : α} (s) : p a → filter p (a::s) = a :: filter p s :=
id                                                       └────┘   └┘    └┘ └────┘  
src                                                         └────┘     └┘      └┘ └────┘
typ                                                      └────┘   └┘    └┘ └────┘  
doc    └──┘                                                 └────┘     └┘       └┘ └────┘
1359  quot.induction_on s $ λ l h, congr_arg coe $ filter_cons_of_pos l h
id   └───────────────┘         └───────┘ └─┘   └────────────────┘  
src  └───────────────┘            └───────┘ └─┘   └────────────────┘
typ  └───────────────┘         └───────┘ └─┘   └────────────────┘  
1360  
1361  @[simp] theorem filter_cons_of_neg {a : α} (s) : ¬ p a → filter p (a::s) = filter p s :=
id                                                        └────┘   └┘   └────┘  
src                                                          └────┘     └┘    └────┘
typ                                                       └────┘   └┘   └────┘  
doc    └──┘                                                   └────┘     └┘     └────┘
1362  quot.induction_on s $ λ l h, @congr_arg _ _ _ _ coe $ filter_cons_of_neg l h
id   └───────────────┘          └───────┘         └─┘   └────────────────┘  
src  └───────────────┘             └───────┘         └─┘   └────────────────┘
typ  └───────────────┘          └───────┘         └─┘   └────────────────┘  
1363  
1364  lemma filter_congr {p q : α → Prop} [decidable_pred p] [decidable_pred q]
id                                       └────────────┘    └────────────┘ 
src                                       └────────────┘     └────────────┘
typ                                      └────────────┘    └────────────┘ 
1365    {s : multiset α} : (∀ x ∈ s, p x ↔ q x) → filter p s = filter q s :=
id          └──────┘                     └────┘    └────┘  
src         └──────┘                            └────┘      └────┘
typ         └──────┘                     └────┘    └────┘  
doc         └──────┘                             └────┘       └────┘
1366  quot.induction_on s $ λ l h, congr_arg coe $ filter_congr h
id   └───────────────┘         └───────┘ └─┘   └──────────┘ 
src  └───────────────┘            └───────┘ └─┘   └──────────┘
typ  └───────────────┘         └───────┘ └─┘   └──────────┘ 
1367  
1368  @[simp] theorem filter_add (s t : multiset α) :
id                                     └──────┘ 
src                                    └──────┘
typ                                    └──────┘ 
doc    └──┘                            └──────┘
1369    filter p (s + t) = filter p s + filter p t :=
id     └────┘        └────┘    └────┘  
src    └────┘           └────┘      └────┘
typ    └────┘        └────┘    └────┘  
doc    └────┘             └────┘       └────┘
1370  quotient.induction_on₂ s t $ λ l₁ l₂, congr_arg coe $ filter_append _ _
id   └────────────────────┘       └┘ └┘  └───────┘ └─┘   └───────────┘
src  └────────────────────┘                └───────┘ └─┘   └───────────┘
typ  └────────────────────┘       └┘ └┘  └───────┘ └─┘   └───────────┘
1371  
1372  @[simp] theorem filter_le (s : multiset α) : filter p s ≤ s :=
id                                  └──────┘     └────┘    
src                                 └──────┘      └────┘     
typ                                 └──────┘     └────┘    
doc    └──┘                         └──────┘      └────┘
1373  quot.induction_on s $ λ l, subperm_of_sublist $ filter_sublist _
id   └───────────────┘        └────────────────┘   └────────────┘
src  └───────────────┘          └────────────────┘   └────────────┘
typ  └───────────────┘        └────────────────┘   └────────────┘
1374  
1375  @[simp] theorem filter_subset (s : multiset α) : filter p s ⊆ s :=
id                                      └──────┘     └────┘    
src                                     └──────┘      └────┘     
typ                                     └──────┘     └────┘    
doc    └──┘                             └──────┘      └────┘
1376  subset_of_le $ filter_le _
id   └──────────┘   └───────┘
src  └──────────┘   └───────┘
typ  └──────────┘   └───────┘
1377  
1378  @[simp] theorem mem_filter {a : α} {s} : a ∈ filter p s ↔ a ∈ s ∧ p a :=
id                                             └────┘         
src                                              └────┘           
typ                                            └────┘         
doc    └──┘                                       └────┘
1379  quot.induction_on s $ λ l, mem_filter
id   └───────────────┘        └────────┘
src  └───────────────┘          └────────┘
typ  └───────────────┘        └────────┘
1380  
1381  theorem of_mem_filter {a : α} {s} (h : a ∈ filter p s) : p a :=
id                                           └────┘       
src                                            └────┘
typ                                          └────┘       
doc                                             └────┘
1382  (mem_filter.1 h).2
id    └────────┘   
src   └────────┘    
typ   └────────┘   
1383  
1384  theorem mem_of_mem_filter {a : α} {s} (h : a ∈ filter p s) : a ∈ s :=
id                                               └────┘        
src                                                └────┘          
typ                                              └────┘        
doc                                                 └────┘
1385  (mem_filter.1 h).1
id    └────────┘   
src   └────────┘    
typ   └────────┘   
1386  
1387  theorem mem_filter_of_mem {a : α} {l} (m : a ∈ l) (h : p a) : a ∈ filter p l :=
id                                                             └────┘  
src                                                                  └────┘
typ                                                            └────┘  
doc                                                                    └────┘
1388  mem_filter.2 ⟨m, h⟩
id   └────────┘     
src  └────────┘
typ  └────────┘     
1389  
1390  theorem filter_eq_self {s} : filter p s = s ↔ ∀ a ∈ s, p a :=
id                                └────┘              
src                               └────┘        
typ                               └────┘              
doc                               └────┘
1391  quot.induction_on s $ λ l, iff.trans ⟨λ h,
id   └───────────────┘        └───────┘    
src  └───────────────┘          └───────┘
typ  └───────────────┘        └───────┘    
1392    eq_of_sublist_of_length_eq (filter_sublist _) (@congr_arg _ _ _ _ card h),
id     └────────────────────────┘  └────────────┘      └───────┘         └──┘ 
src    └────────────────────────┘  └────────────┘      └───────┘         └──┘
typ    └────────────────────────┘  └────────────┘      └───────┘         └──┘ 
doc                                                                      └──┘
1393    congr_arg coe⟩ filter_eq_self
id     └───────┘ └─┘  └────────────┘
src    └───────┘ └─┘  └────────────┘
typ    └───────┘ └─┘  └────────────┘
1394  
1395  theorem filter_eq_nil {s} : filter p s = 0 ↔ ∀ a ∈ s, ¬p a :=
id                               └────┘               
src                              └────┘                  
typ                              └────┘               
doc                              └────┘
1396  quot.induction_on s $ λ l, iff.trans ⟨λ h,
id   └───────────────┘        └───────┘    
src  └───────────────┘          └───────┘
typ  └───────────────┘        └───────┘    
1397    eq_nil_of_length_eq_zero (@congr_arg _ _ _ _ card h),
id     └──────────────────────┘   └───────┘         └──┘ 
src    └──────────────────────┘   └───────┘         └──┘
typ    └──────────────────────┘   └───────┘         └──┘ 
doc                                                 └──┘
1398    congr_arg coe⟩ filter_eq_nil
id     └───────┘ └─┘  └───────────┘
src    └───────┘ └─┘  └───────────┘
typ    └───────┘ └─┘  └───────────┘
1399  
1400  theorem filter_le_filter {s t} (h : s ≤ t) : filter p s ≤ filter p t :=
id                                             └────┘    └────┘  
src                                              └────┘      └────┘
typ                                            └────┘    └────┘  
doc                                               └────┘       └────┘
1401  le_induction_on h $ λ l₁ l₂ h, subperm_of_sublist $ filter_sublist_filter h
id   └─────────────┘      └┘ └┘   └────────────────┘   └───────────────────┘ 
src  └─────────────┘                └────────────────┘   └───────────────────┘
typ  └─────────────┘      └┘ └┘   └────────────────┘   └───────────────────┘ 
1402  
1403  theorem le_filter {s t} : s ≤ filter p t ↔ s ≤ t ∧ ∀ a ∈ s, p a :=
id                               └────┘                
src                               └────┘           
typ                              └────┘                
doc                                └────┘
1404  ⟨λ h, ⟨le_trans h (filter_le _), λ a m, of_mem_filter (mem_of_le h m)⟩,
id         └──────┘   └───────┘          └───────────┘  └───────┘  
src         └──────┘    └───────┘            └───────────┘  └───────┘
typ        └──────┘   └───────┘          └───────────┘  └───────┘  
1405   λ ⟨h, al⟩, filter_eq_self.2 al ▸ filter_le_filter h⟩
id        └┘   └────────────┘      └──────────────┘
src              └────────────┘      └──────────────┘
typ       └┘   └────────────┘      └──────────────┘
1406  
1407  @[simp] theorem filter_sub [decidable_eq α] (s t : multiset α) :
id                               └──────────┘          └──────┘ 
src                              └──────────┘           └──────┘
typ                              └──────────┘          └──────┘ 
doc    └──┘                                             └──────┘
1408    filter p (s - t) = filter p s - filter p t :=
id     └────┘        └────┘    └────┘  
src    └────┘           └────┘      └────┘
typ    └────┘        └────┘    └────┘  
doc    └────┘             └────┘       └────┘
1409  begin
st   └─────
1410    revert s, refine multiset.induction_on t (by simp) (λ a t IH s, _),
id                      └───────────────────┘ 
src    └──────┘  └─────┘└───────────────────┘    └──┘└┘  └───────────┘
typ    └──────┘  └─────┘└───────────────────┘   └──┘└┘  └───────────┘
doc    └──────┘  └─────┘                         └──┘└┘  └───────────┘
txt    └──────┘  └─────┘                         └──┘└┘  └───────────┘
par    └──────┘  └─────┘                         └──┘└┘  └───────────┘
pid          └┘                                 └─────┘  └───────────┘
st   ─────────┘└──────────────────────────────────┘└───┘└───────────────┘└─
1411    rw [sub_cons, IH],
id         └──────┘  └┘
src    └──┘└──────┘└┘  
typ    └──┘└──────┘└┘└┘
doc    └──┘        └┘  
txt    └──┘        └┘  
par    └──┘        └┘  
pid      └┘        └┘  
st   ─────────────┘└──┘└──
1412    by_cases p a,
id               
src    └───────┘ 
typ    └───────┘
doc    └───────┘ 
txt    └───────┘ 
par    └───────┘ 
pid             
st   ─────────────┘└─
1413    { rw [filter_cons_of_pos _ h, sub_cons], congr,
id           └────────────────┘     └──────┘
src      └──┘└────────────────┘└─┘ └┘└──────┘  └───┘
typ      └──┘└────────────────┘└─┘└┘└──────┘  └───┘
doc      └──┘                  └─┘ └┘        
txt      └──┘                  └─┘ └┘          └───┘
par      └──┘                  └─┘ └┘          └───┘
pid        └┘                  └─┘ └┘        
st   ───┘└────────────────────────┘└────────┘└──────┘└─
1414      by_cases m : a ∈ s,
id                      
src      └───────┘ └─┘ 
typ      └───────┘ └─┘
doc      └───────┘ └─┘  
txt      └───────┘ └─┘  
par      └───────┘ └─┘  
pid               └─┘  
st   ─────────────────────┘└─
1415      { rw [← cons_inj_right a, ← filter_cons_of_pos _ h,
id               └────────────┘     └────────────────┘   
src        └────┘└────────────┘ └──┘└────────────────┘└─┘ └─
typ        └────┘└────────────┘└──┘└────────────────┘└─┘└─
doc        └────┘               └──┘                  └─┘ └─
txt        └────┘               └──┘                  └─┘ └─
par        └────┘               └──┘                  └─┘ └─
pid          └──┘               └──┘                  └─┘ └─
st   ─────┘└────────────────────┘└────────────────────────┘└─
1416            cons_erase (mem_filter_of_mem m h), cons_erase m] },
id             └────────┘  └───────────────┘     └────────┘ 
src  ─────────┘└────────┘ └───────────────┘  └─┘└────────┘ └┘
typ  ─────────┘└────────┘ └───────────────┘└─┘└────────┘└┘
doc  ─────────┘                              └─┘           └┘
txt  ─────────┘                              └─┘           └┘
par  ─────────┘                              └─┘           └┘
pid  ─────────┘                              └─┘           
st   ───────────────────────────────────────────┘└────────────┘└┘
1417      { rw [erase_of_not_mem m, erase_of_not_mem (mt mem_of_mem_filter m)] } },
id             └──────────────┘   └──────────────┘  └┘ └───────────────┘ 
src        └──┘└──────────────┘ └┘└──────────────┘ └┘└───────────────┘ └─┘
typ        └──┘└──────────────┘└┘└──────────────┘ └┘└───────────────┘└─┘
doc        └──┘                 └┘                                     └─┘
txt        └──┘                 └┘                                     └─┘
par        └──┘                 └┘                                     └─┘
pid          └┘                 └┘                                     └┘
st   ───────────────────────────┘└─────────────────────────────────────────┘└──┘
1418    { rw [filter_cons_of_neg _ h],
id           └────────────────┘   
src      └──┘└────────────────┘└─┘ 
typ      └──┘└────────────────┘└─┘
doc      └──┘                  └─┘ 
txt      └──┘                  └─┘ 
par      └──┘                  └─┘ 
pid        └┘                  └─┘ 
st   ─────────────────────────────┘└──
1419      by_cases m : a ∈ s,
id                       
src      └───────┘ └─┘  
typ      └───────┘ └─┘ 
doc      └───────┘ └─┘  
txt      └───────┘ └─┘  
par      └───────┘ └─┘  
pid               └─┘  
st   ─────────────────────┘└─
1420      { rw [(by rw filter_cons_of_neg _ h : filter p (erase s a) = filter p (a :: erase s a)),
id                    └────────────────┘                            └────┘     └┘ └───┘  
src        └──┘   └──┘└────────────────┘└─┘ └─┘               └┘└────┘   └┘└───┘  └───
typ        └──┘   └──┘└────────────────┘└─┘└─┘               └┘└────┘  └┘└───┘└───
doc        └──┘   └──┘                  └─┘ └─┘               └┘ └────┘   └┘└───┘  └───
txt        └──┘   └──┘                  └─┘ └─┘               └┘                   └───
par        └──┘   └──┘                  └─┘ └─┘               └┘                   └───
pid          └┘   └──┘                  └─┘ └─┘               └┘                   └───
st   ─────┘└─────┘└─────────────────────────┘└─────────────────────────────────────────────────┘└─
1421            cons_erase m] },
id             └────────┘ 
src  ─────────┘└────────┘ └┘
typ  ─────────┘└────────┘└┘
doc  ─────────┘           └┘
txt  ─────────┘           └┘
par  ─────────┘           └┘
pid  ─────────┘           
st   ─────────────────────┘└┘
1422      { rw [erase_of_not_mem m] } }
id             └──────────────┘ 
src        └──┘└──────────────┘ └┘
typ        └──┘└──────────────┘└┘
doc        └──┘                 └┘
txt        └──┘                 └┘
par        └──┘                 └┘
pid          └┘                 
st   ───────────────────────────┘└───
1423  end
st   ──┘
1424  
1425  @[simp] theorem filter_union [decidable_eq α] (s t : multiset α) :
id                                 └──────────┘          └──────┘ 
src                                └──────────┘           └──────┘
typ                                └──────────┘          └──────┘ 
doc    └──┘                                               └──────┘
1426    filter p (s ∪ t) = filter p s ∪ filter p t :=
id     └────┘        └────┘    └────┘  
src    └────┘           └────┘      └────┘
typ    └────┘        └────┘    └────┘  
doc    └────┘             └────┘       └────┘
1427  by simp [(∪), union]
id                 └───┘
src     └────┘ └──┘└───┘└─
typ     └────┘ └──┘└───┘└─
doc     └────┘ └──┘└───┘└─
txt     └────┘ └──┘     └─
par     └────┘ └──┘     └─
pid          └──┘     
st     └──────────────────
1428  
src  
typ  
doc  
txt  
par  
pid  
st   
1429  @[simp] theorem filter_inter [decidable_eq α] (s t : multiset α) :
id                                 └──────────┘          └──────┘ 
src                                └──────────┘           └──────┘
typ                                └──────────┘          └──────┘ 
doc    └──┘                                               └──────┘
1430    filter p (s ∩ t) = filter p s ∩ filter p t :=
id     └────┘        └────┘    └────┘  
src    └────┘           └────┘      └────┘
typ    └────┘        └────┘    └────┘  
doc    └────┘             └────┘       └────┘
1431  le_antisymm (le_inter
id   └─────────┘  └──────┘
src  └─────────┘  └──────┘
typ  └─────────┘  └──────┘
1432      (filter_le_filter $ inter_le_left _ _)
id        └──────────────┘   └───────────┘
src       └──────────────┘   └───────────┘
typ       └──────────────┘   └───────────┘
1433      (filter_le_filter $ inter_le_right _ _)) $ le_filter.2
id        └──────────────┘   └────────────┘         └───────┘
src       └──────────────┘   └────────────┘         └───────┘
typ       └──────────────┘   └────────────┘         └───────┘
1434  ⟨inf_le_inf (filter_le _) (filter_le _),
id    └────────┘  └───────┘     └───────┘
src   └────────┘  └───────┘     └───────┘
typ   └────────┘  └───────┘     └───────┘
1435    λ a h, of_mem_filter (mem_of_le (inter_le_left _ _) h)⟩
id          └───────────┘  └───────┘  └───────────┘      
src           └───────────┘  └───────┘  └───────────┘
typ         └───────────┘  └───────┘  └───────────┘      
1436  
1437  @[simp] theorem filter_filter {q} [decidable_pred q] (s : multiset α) :
id                                      └────────────┘        └──────┘ 
src                                     └────────────┘         └──────┘
typ                                     └────────────┘        └──────┘ 
doc    └──┘                                                    └──────┘
1438    filter p (filter q s) = filter (λ a, p a ∧ q a) s :=
id     └────┘   └────┘     └────┘            
src    └────┘    └────┘       └────┘           
typ    └────┘   └────┘     └────┘            
doc    └────┘    └────┘        └────┘
1439  quot.induction_on s $ λ l, congr_arg coe $ filter_filter l
id   └───────────────┘        └───────┘ └─┘   └───────────┘ 
src  └───────────────┘          └───────┘ └─┘   └───────────┘
typ  └───────────────┘        └───────┘ └─┘   └───────────┘ 
1440  
1441  theorem filter_add_filter {q} [decidable_pred q] (s : multiset α) :
id                                  └────────────┘        └──────┘ 
src                                 └────────────┘         └──────┘
typ                                 └────────────┘        └──────┘ 
doc                                                        └──────┘
1442    filter p s + filter q s = filter (λ a, p a ∨ q a) s + filter (λ a, p a ∧ q a) s :=
id     └────┘    └────┘    └────┘              └────┘            
src    └────┘      └────┘      └────┘                    └────┘           
typ    └────┘    └────┘    └────┘              └────┘            
doc    └────┘       └────┘       └────┘                      └────┘
1443  multiset.induction_on s rfl $ λ a s IH,
id   └───────────────────┘  └─┘       └┘
src  └───────────────────┘   └─┘
typ  └───────────────────┘  └─┘       └┘
1444  by by_cases p a; by_cases q a; simp *
id                            
src     └───────┘    └───────┘    └──────
typ     └───────┘  └───────┘  └──────
doc     └───────┘    └───────┘    └──────
txt     └───────┘    └───────┘    └──────
par     └───────┘    └───────┘    └──────
pid                                 
st     └───────────────────────────────────
1445  
src  
typ  
doc  
txt  
par  
pid  
st   
1446  theorem filter_add_not (s : multiset α) :
id                               └──────┘ 
src                              └──────┘
typ                              └──────┘ 
doc                              └──────┘
1447    filter p s + filter (λ a, ¬ p a) s = s :=
id     └────┘    └────┘            
src    └────┘      └────┘               
typ    └────┘    └────┘            
doc    └────┘       └────┘
1448  by rw [filter_add_filter, filter_eq_self.2, filter_eq_nil.2]; simp [decidable.em]
id          └───────────────┘  └────────────┘    └───────────┘           └──────────┘
src     └──┘└───────────────┘└┘└────────────┘└──┘└───────────┘└─┘  └────┘└──────────┘└─
typ     └──┘└───────────────┘└┘└────────────┘└──┘└───────────┘└─┘  └────┘└──────────┘└─
doc     └──┘                 └┘              └──┘             └─┘  └────┘            └─
txt     └──┘                 └┘              └──┘             └─┘  └────┘            └─
par     └──┘                 └┘              └──┘             └─┘  └────┘            └─
pid       └┘                 └┘              └──┘             └─┘                  
st     └────────────────────┘└──────────────┘└───────────────┘└─┘└─────────────────────
1449  
src  
typ  
doc  
txt  
par  
pid  
st   
1450  /- filter_map -/
src  ─────────────────
typ  ─────────────────
doc  ─────────────────
txt  ─────────────────
par  ─────────────────
pid  ─────────────────
st   ─────────────────
1451  
src  
typ  
doc  
txt  
par  
pid  
st   
1452  /-- `filter_map f s` is a combination filter/map operation on `s`.
1453    The function `f : α → option β` is applied to each element of `s`;
1454    if `f a` is `some b` then `b` is added to the result, otherwise
1455    `a` is removed from the resulting multiset. -/
1456  def filter_map (f : α → option β) (s : multiset α) : multiset β :=
id                          └────┘        └──────┘     └──────┘ 
src                          └────┘         └──────┘      └──────┘
typ                         └────┘        └──────┘     └──────┘ 
doc                                         └──────┘      └──────┘
1457  quot.lift_on s (λ l, (filter_map f l : multiset β))
id   └──────────┘        └────────┘     └──────┘ 
src  └──────────┘          └────────┘       └──────┘
typ  └──────────┘        └────────┘     └──────┘ 
doc                                         └──────┘
1458    (λ l₁ l₂ h, quot.sound $perm_filter_map f h)
id        └┘ └┘   └────────┘  └─────────────┘  
src                └────────┘  └─────────────┘
typ       └┘ └┘   └────────┘  └─────────────┘  
1459  
1460  @[simp] theorem coe_filter_map (f : α → option β) (l : list α) : filter_map f l = l.filter_map f := rfl
id                                          └────┘        └──┘     └────────┘    └─────────┘     └─┘
src                                          └────┘         └──┘      └────────┘       └─────────┘      └─┘
typ                                         └────┘        └──┘     └────────┘    └─────────┘     └─┘
doc    └──┘                                                           └────────┘
1461  
1462  @[simp] theorem filter_map_zero (f : α → option β) : filter_map f 0 = 0 := rfl
id                                           └────┘     └────────┘          └─┘
src                                           └────┘      └────────┘           └─┘
typ                                          └────┘     └────────┘          └─┘
doc    └──┘                                               └────────┘
1463  
1464  @[simp] theorem filter_map_cons_none {f : α → option β} (a : α) (s : multiset α) (h : f a = none) :
id                                                └────┘               └──────┘           └──┘
src                                                └────┘                 └──────┘              └──┘
typ                                               └────┘               └──────┘           └──┘
doc    └──┘                                                               └──────┘
1465    filter_map f (a :: s) = filter_map f s :=
id     └────────┘    └┘    └────────┘  
src    └────────┘      └┘     └────────┘
typ    └────────┘    └┘    └────────┘  
doc    └────────┘      └┘      └────────┘
1466  quot.induction_on s $ λ l, @congr_arg _ _ _ _ coe $ filter_map_cons_none a l h
id   └───────────────┘         └───────┘         └─┘   └──────────────────┘   
src  └───────────────┘           └───────┘         └─┘   └──────────────────┘
typ  └───────────────┘         └───────┘         └─┘   └──────────────────┘   
1467  
1468  @[simp] theorem filter_map_cons_some (f : α → option β)
id                                                └────┘ 
src                                                └────┘
typ                                               └────┘ 
doc    └──┘
1469    (a : α) (s : multiset α) {b : β} (h : f a = some b) :
id                 └──────┘                  └──┘ 
src                 └──────┘                      └──┘
typ                └──────┘                  └──┘ 
doc                 └──────┘
1470    filter_map f (a :: s) = b :: filter_map f s :=
id     └────────┘    └┘     └┘ └────────┘  
src    └────────┘      └┘       └┘ └────────┘
typ    └────────┘    └┘     └┘ └────────┘  
doc    └────────┘      └┘        └┘ └────────┘
1471  quot.induction_on s $ λ l, @congr_arg _ _ _ _ coe $ filter_map_cons_some f a l h
id   └───────────────┘         └───────┘         └─┘   └──────────────────┘    
src  └───────────────┘           └───────┘         └─┘   └──────────────────┘
typ  └───────────────┘         └───────┘         └─┘   └──────────────────┘    
1472  
1473  theorem filter_map_eq_map (f : α → β) : filter_map (some ∘ f) = map f :=
id                                         └────────┘  └──┘     └─┘ 
src                                          └────────┘  └──┘      └─┘
typ                                        └────────┘  └──┘     └─┘ 
doc                                          └────────┘              └─┘
1474  funext $ λ s, quot.induction_on s $ λ l,
id   └────┘       └───────────────┘      
src  └────┘        └───────────────┘
typ  └────┘       └───────────────┘      
1475  @congr_arg _ _ _ _ coe $ congr_fun (filter_map_eq_map f) l
id    └───────┘         └─┘   └───────┘  └───────────────┘   
src   └───────┘         └─┘   └───────┘  └───────────────┘
typ   └───────┘         └─┘   └───────┘  └───────────────┘   
1476  
1477  theorem filter_map_eq_filter (p : α → Prop) [decidable_pred p] :
id                                               └────────────┘ 
src                                               └────────────┘
typ                                              └────────────┘ 
1478    filter_map (option.guard p) = filter p :=
id     └────────┘  └──────────┘    └────┘ 
src    └────────┘  └──────────┘     └────┘
typ    └────────┘  └──────────┘    └────┘ 
doc    └────────┘  └──────────┘      └────┘
1479  funext $ λ s, quot.induction_on s $ λ l,
id   └────┘       └───────────────┘      
src  └────┘        └───────────────┘
typ  └────┘       └───────────────┘      
1480  @congr_arg _ _ _ _ coe $ congr_fun (filter_map_eq_filter p) l
id    └───────┘         └─┘   └───────┘  └──────────────────┘   
src   └───────┘         └─┘   └───────┘  └──────────────────┘
typ   └───────┘         └─┘   └───────┘  └──────────────────┘   
1481  
1482  theorem filter_map_filter_map (f : α → option β) (g : β → option γ) (s : multiset α) :
id                                         └────┘           └────┘        └──────┘ 
src                                         └────┘             └────┘         └──────┘
typ                                        └────┘           └────┘        └──────┘ 
doc                                                                           └──────┘
1483    filter_map g (filter_map f s) = filter_map (λ x, (f x).bind g) s :=
id     └────────┘   └────────┘     └────────┘         └──┘    
src    └────────┘    └────────┘       └────────┘            └──┘
typ    └────────┘   └────────┘     └────────┘         └──┘    
doc    └────────┘    └────────┘        └────────┘
1484  quot.induction_on s $ λ l, congr_arg coe $ filter_map_filter_map f g l
id   └───────────────┘        └───────┘ └─┘   └───────────────────┘   
src  └───────────────┘          └───────┘ └─┘   └───────────────────┘
typ  └───────────────┘        └───────┘ └─┘   └───────────────────┘   
1485  
1486  theorem map_filter_map (f : α → option β) (g : β → γ) (s : multiset α) :
id                                  └────┘                  └──────┘ 
src                                  └────┘                     └──────┘
typ                                 └────┘                  └──────┘ 
doc                                                             └──────┘
1487    map g (filter_map f s) = filter_map (λ x, (f x).map g) s :=
id     └─┘   └────────┘     └────────┘         └─┘    
src    └─┘    └────────┘       └────────┘            └─┘
typ    └─┘   └────────┘     └────────┘         └─┘    
doc    └─┘    └────────┘        └────────┘
1488  quot.induction_on s $ λ l, congr_arg coe $ map_filter_map f g l
id   └───────────────┘        └───────┘ └─┘   └────────────┘   
src  └───────────────┘          └───────┘ └─┘   └────────────┘
typ  └───────────────┘        └───────┘ └─┘   └────────────┘   
1489  
1490  theorem filter_map_map (f : α → β) (g : β → option γ) (s : multiset α) :
id                                            └────┘        └──────┘ 
src                                              └────┘         └──────┘
typ                                           └────┘        └──────┘ 
doc                                                             └──────┘
1491    filter_map g (map f s) = filter_map (g ∘ f) s :=
id     └────────┘   └─┘     └────────┘      
src    └────────┘    └─┘       └────────┘    
typ    └────────┘   └─┘     └────────┘      
doc    └────────┘    └─┘        └────────┘
1492  quot.induction_on s $ λ l, congr_arg coe $ filter_map_map f g l
id   └───────────────┘        └───────┘ └─┘   └────────────┘   
src  └───────────────┘          └───────┘ └─┘   └────────────┘
typ  └───────────────┘        └───────┘ └─┘   └────────────┘   
1493  
1494  theorem filter_filter_map (f : α → option β) (p : β → Prop) [decidable_pred p] (s : multiset α) :
id                                     └────┘                  └────────────┘        └──────┘ 
src                                     └────┘                    └────────────┘         └──────┘
typ                                    └────┘                  └────────────┘        └──────┘ 
doc                                                                                      └──────┘
1495    filter p (filter_map f s) = filter_map (λ x, (f x).filter p) s :=
id     └────┘   └────────┘     └────────┘         └────┘    
src    └────┘    └────────┘       └────────┘            └────┘
typ    └────┘   └────────┘     └────────┘         └────┘    
doc    └────┘    └────────┘        └────────┘            └────┘
1496  quot.induction_on s $ λ l, congr_arg coe $ filter_filter_map f p l
id   └───────────────┘        └───────┘ └─┘   └───────────────┘   
src  └───────────────┘          └───────┘ └─┘   └───────────────┘
typ  └───────────────┘        └───────┘ └─┘   └───────────────┘   
1497  
1498  theorem filter_map_filter (p : α → Prop) [decidable_pred p] (f : α → option β) (s : multiset α) :
id                                            └────────────┘           └────┘        └──────┘ 
src                                            └────────────┘             └────┘         └──────┘
typ                                           └────────────┘           └────┘        └──────┘ 
doc                                                                                      └──────┘
1499    filter_map f (filter p s) = filter_map (λ x, if p x then f x else none) s :=
id     └────────┘   └────┘     └────────┘                       └──┘  
src    └────────┘    └────┘       └────────┘                            └──┘
typ    └────────┘   └────┘     └────────┘                       └──┘  
doc    └────────┘    └────┘        └────────┘
1500  quot.induction_on s $ λ l, congr_arg coe $ filter_map_filter p f l
id   └───────────────┘        └───────┘ └─┘   └───────────────┘   
src  └───────────────┘          └───────┘ └─┘   └───────────────┘
typ  └───────────────┘        └───────┘ └─┘   └───────────────┘   
1501  
1502  @[simp] theorem filter_map_some (s : multiset α) : filter_map some s = s :=
id                                        └──────┘     └────────┘ └──┘   
src                                       └──────┘      └────────┘ └──┘   
typ                                       └──────┘     └────────┘ └──┘   
doc    └──┘                               └──────┘      └────────┘
1503  quot.induction_on s $ λ l, congr_arg coe $ filter_map_some l
id   └───────────────┘        └───────┘ └─┘   └─────────────┘ 
src  └───────────────┘          └───────┘ └─┘   └─────────────┘
typ  └───────────────┘        └───────┘ └─┘   └─────────────┘ 
1504  
1505  @[simp] theorem mem_filter_map (f : α → option β) (s : multiset α) {b : β} :
id                                          └────┘        └──────┘        
src                                          └────┘         └──────┘
typ                                         └────┘        └──────┘        
doc    └──┘                                                 └──────┘
1506    b ∈ filter_map f s ↔ ∃ a, a ∈ s ∧ f a = some b :=
id       └────────┘             └──┘ 
src       └────────┘                    └──┘
typ      └────────┘             └──┘ 
doc        └────────┘
1507  quot.induction_on s $ λ l, mem_filter_map f l
id   └───────────────┘        └────────────┘  
src  └───────────────┘          └────────────┘
typ  └───────────────┘        └────────────┘  
1508  
1509  theorem map_filter_map_of_inv (f : α → option β) (g : β → α)
id                                         └────┘           
src                                         └────┘
typ                                        └────┘           
1510    (H : ∀ x : α, (f x).map g = some x) (s : multiset α) :
id                     └─┘    └──┘        └──────┘ 
src                       └─┘     └──┘         └──────┘
typ                    └─┘    └──┘        └──────┘ 
doc                                             └──────┘
1511    map g (filter_map f s) = s :=
id     └─┘   └────────┘     
src    └─┘    └────────┘      
typ    └─┘   └────────┘     
doc    └─┘    └────────┘
1512  quot.induction_on s $ λ l, congr_arg coe $ map_filter_map_of_inv f g H l
id   └───────────────┘        └───────┘ └─┘   └───────────────────┘    
src  └───────────────┘          └───────┘ └─┘   └───────────────────┘
typ  └───────────────┘        └───────┘ └─┘   └───────────────────┘    
1513  
1514  theorem filter_map_le_filter_map (f : α → option β) {s t : multiset α}
id                                            └────┘          └──────┘ 
src                                            └────┘           └──────┘
typ                                           └────┘          └──────┘ 
doc                                                             └──────┘
1515    (h : s ≤ t) : filter_map f s ≤ filter_map f t :=
id                └────────┘    └────────┘  
src                 └────────┘      └────────┘
typ               └────────┘    └────────┘  
doc                  └────────┘       └────────┘
1516  le_induction_on h $ λ l₁ l₂ h,
id   └─────────────┘      └┘ └┘ 
src  └─────────────┘
typ  └─────────────┘      └┘ └┘ 
1517  subperm_of_sublist $ filter_map_sublist_filter_map _ h
id   └────────────────┘   └───────────────────────────┘   
src  └────────────────┘   └───────────────────────────┘
typ  └────────────────┘   └───────────────────────────┘   
1518  
1519  /- powerset -/
1520  
1521  def powerset_aux (l : list α) : list (multiset α) :=
id                         └──┘     └──┘  └──────┘ 
src                        └──┘      └──┘  └──────┘
typ                        └──┘     └──┘  └──────┘ 
doc                                        └──────┘
1522  0 :: sublists_aux l (λ x y, x :: y)
id     └┘ └──────────┘         └┘ 
src    └┘ └──────────┘             └┘
typ    └┘ └──────────┘         └┘ 
1523  
1524  theorem powerset_aux_eq_map_coe {l : list α} :
id                                        └──┘ 
src                                       └──┘
typ                                       └──┘ 
1525    powerset_aux l = (sublists l).map coe :=
id     └──────────┘    └──────┘  └─┘  └─┘
src    └──────────┘     └──────┘   └─┘  └─┘
typ    └──────────┘    └──────┘  └─┘  └─┘
doc                      └──────┘
1526  by simp [powerset_aux, sublists];
id            └──────────┘  └──────┘
src     └────┘└──────────┘└┘└──────┘
typ     └────┘└──────────┘└┘└──────┘
doc     └────┘            └┘└──────┘
txt     └────┘            └┘        
par     └────┘            └┘        
pid                     └┘        
st     └───────────────────────────────
1527     rw [← show @sublists_aux₁ α (multiset α) l (λ x, [↑x]) =
id                  └───────────┘    └──────┘              
src     └────┘     └───────────┘  └──────┘ └┘   └──┘ └┘
typ     └────┘     └───────────┘  └──────┘└┘   └──┘ └┘
doc     └────┘                    └──────┘ └┘   └──┘    └┘ 
txt     └────┘                             └┘   └──┘    └┘ 
par     └────┘                             └┘   └──┘    └┘ 
pid       └──┘                             └┘   └──┘    └┘ 
st   ──────┘└────────────────────────────────────────────────────
1528                sublists_aux l (λ x, list.cons ↑x),
id                 └──────────┘        └───────┘
src  ─────────────┘└──────────┘   └──┘└───────┘  └──
typ  ─────────────┘└──────────┘  └──┘└───────┘  └──
doc  ─────────────┘               └──┘           └──
txt  ─────────────┘               └──┘           └──
par  ─────────────┘               └──┘           └──
pid  ─────────────┘               └──┘           └──
st   ──────────────────────────────────────────────────
1529           from sublists_aux₁_eq_sublists_aux _ _,
id                 └───────────────────────────┘
src  ─────────────┘└───────────────────────────┘└─────
typ  ─────────────┘└───────────────────────────┘└─────
doc  ─────────────┘                             └─────
txt  ─────────────┘                             └─────
par  ─────────────┘                             └─────
pid  ─────────────┘                             └─────
st   ──────────────────────────────────────────────┘└─
1530         sublists_aux_cons_eq_sublists_aux₁,
id          └────────────────────────────────┘
src  ──────┘└────────────────────────────────┘└─
typ  ──────┘└────────────────────────────────┘└─
doc  ──────┘                                  └─
txt  ──────┘                                  └─
par  ──────┘                                  └─
pid  ──────┘                                  └─
st   ────────────────────────────────────────┘└─
1531         ← bind_ret_eq_map, sublists_aux₁_bind]; refl
id            └─────────────┘  └────────────────┘
src  ────────┘└─────────────┘└┘└────────────────┘  └────
typ  ────────┘└─────────────┘└┘└────────────────┘  └────
doc  ────────┘               └┘                    └────
txt  ────────┘               └┘                    └────
par  ────────┘               └┘                    └────
pid  ────────┘               └┘                        
st   ───────────────────────┘└──────────────────┘└──────
1532  
src  
typ  
doc  
txt  
par  
pid  
st   
1533  @[simp] theorem mem_powerset_aux {l : list α} {s} :
id                                         └──┘ 
src                                        └──┘
typ                                        └──┘ 
doc    └──┘
1534    s ∈ powerset_aux l ↔ s ≤ ↑l :=
id       └──────────┘     
src       └──────────┘       
typ      └──────────┘     
1535  quotient.induction_on s $
id   └───────────────────┘ 
src  └───────────────────┘
typ  └───────────────────┘ 
1536  by simp [powerset_aux_eq_map_coe, subperm, and.comm]
id            └─────────────────────┘  └─────┘  └──────┘
src     └────┘└─────────────────────┘└┘└─────┘└┘└──────┘└─
typ     └────┘└─────────────────────┘└┘└─────┘└┘└──────┘└─
doc     └────┘                       └┘└─────┘└┘        └─
txt     └────┘                       └┘       └┘        └─
par     └────┘                       └┘       └┘        └─
pid                                └┘       └┘        
st     └──────────────────────────────────────────────────
1537  
src  
typ  
doc  
txt  
par  
pid  
st   
1538  def powerset_aux' (l : list α) : list (multiset α) := (sublists' l).map coe
id                          └──┘     └──┘  └──────┘       └───────┘  └─┘  └─┘
src                         └──┘      └──┘  └──────┘        └───────┘   └─┘  └─┘
typ                         └──┘     └──┘  └──────┘       └───────┘  └─┘  └─┘
doc                                         └──────┘        └───────┘
1539  
1540  theorem powerset_aux_perm_powerset_aux' {l : list α} :
id                                                └──┘ 
src                                               └──┘
typ                                               └──┘ 
1541    powerset_aux l ~ powerset_aux' l :=
id     └──────────┘   └───────────┘ 
src    └──────────┘    └───────────┘
typ    └──────────┘   └───────────┘ 
doc                   
1542  by rw powerset_aux_eq_map_coe; exact
id         └─────────────────────┘
src     └─┘└─────────────────────┘  └────┘
typ     └─┘└─────────────────────┘  └────┘
doc     └─┘                         └────┘
txt     └─┘                         └────┘
par     └─┘                         └────┘
pid                                     
st     └──────────────────────────────────
1543  perm_map _ (sublists_perm_sublists' _)
id   └──────┘    └─────────────────────┘
src  └──────┘└─┘ └─────────────────────┘└───
typ  └──────┘└─┘ └─────────────────────┘└───
doc          └─┘                        └───
txt          └─┘                        └───
par          └─┘                        └───
pid          └─┘                        └─┘
st   ───────────────────────────────────────
1544  
src  
typ  
doc  
txt  
par  
pid  
st   
1545  @[simp] theorem powerset_aux'_nil : powerset_aux' (@nil α) = [0] := rfl
id                                       └───────────┘   └─┘         └─┘
src                                      └───────────┘   └─┘          └─┘
typ                                      └───────────┘   └─┘         └─┘
doc    └──┘
1546  
1547  @[simp] theorem powerset_aux'_cons (a : α) (l : list α) :
id                                                  └──┘ 
src                                                  └──┘
typ                                                 └──┘ 
doc    └──┘
1548    powerset_aux' (a::l) = powerset_aux' l ++ list.map (cons a) (powerset_aux' l) :=
id     └───────────┘  └┘   └───────────┘  └┘ └──────┘  └──┘    └───────────┘ 
src    └───────────┘   └┘    └───────────┘   └┘ └──────┘  └──┘     └───────────┘
typ    └───────────┘  └┘   └───────────┘  └┘ └──────┘  └──┘    └───────────┘ 
doc                                                        └──┘
1549  by simp [powerset_aux']; refl
id            └───────────┘
src     └────┘└───────────┘  └────
typ     └────┘└───────────┘  └────
doc     └────┘               └────
txt     └────┘               └────
par     └────┘               └────
pid                            
st     └───────────────────────────
1550  
src  
typ  
doc  
txt  
par  
pid  
st   
1551  theorem powerset_aux'_perm {l₁ l₂ : list α} (p : l₁ ~ l₂) :
id                                       └──┘        └┘  └┘
src                                      └──┘            
typ                                      └──┘        └┘  └┘
doc                                                      
1552    powerset_aux' l₁ ~ powerset_aux' l₂ :=
id     └───────────┘ └┘  └───────────┘ └┘
src    └───────────┘     └───────────┘
typ    └───────────┘ └┘  └───────────┘ └┘
doc                     
1553  begin
st   └─────
1554    induction p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ p₂ IH₁ IH₂, {simp},
id               
src    └────────┘ └─────────────────────────────────────────────┘   └──┘
typ    └────────┘└─────────────────────────────────────────────┘   └──┘
doc    └────────┘ └─────────────────────────────────────────────┘   └──┘
txt    └────────┘ └─────────────────────────────────────────────┘   └──┘
par    └────────┘ └─────────────────────────────────────────────┘   └──┘
pid              └────────────────────────────────────────────┘
st   ───────────────────────────────────────────────────────────┘└─────┘└┘
1555    { simp, exact perm_app IH (perm_map _ IH) },
id                   └──────┘     └──────┘   └┘
src      └──┘  └────┘└──────┘   └──────┘└─┘  └┘
typ      └──┘  └────┘└──────┘   └──────┘└─┘└┘└┘
doc      └──┘  └────┘                   └─┘  └┘
txt      └──┘  └────┘                   └─┘  └┘
par      └──┘  └────┘                   └─┘  └┘
pid                                    └─┘  
st   ───┘└──┘└──────────────────────────────────┘└┘
1556    { simp, apply perm_app_right,
id                   └────────────┘
src      └──┘  └────┘└────────────┘
typ      └──┘  └────┘└────────────┘
doc      └──┘  └────┘
txt      └──┘  └────┘
par      └──┘  └────┘
pid                 
st   ───┘└──┘└────────────────────┘└─
1557      rw [← append_assoc, ← append_assoc,
id             └──────────┘    └──────────┘
src      └────┘└──────────┘└──┘└──────────┘└─
typ      └────┘└──────────┘└──┘└──────────┘└─
doc      └────┘            └──┘            └─
txt      └────┘            └──┘            └─
par      └────┘            └──┘            └─
pid        └──┘            └──┘            └─
st   ─────────────────────┘└──────────────┘└─
1558          (by funext s; simp [cons_swap] : cons b ∘ cons a = cons a ∘ cons b)],
id                               └───────┘                            └──┘ 
src  ───────┘   └──────┘└┘└────┘└───────┘└┘└┘                └──┘ └┘
typ  ───────┘   └──────┘└┘└────┘└───────┘└┘└┘               └──┘└┘
doc  ───────┘   └──────┘└┘└────┘         └┘└┘                  └──┘ └┘
txt  ───────┘   └──────┘└┘└────┘         └┘└┘                       └┘
par  ───────┘   └──────┘└┘└────┘         └┘└┘                       └┘
pid  ───────┘   └───────────────┘         └──┘                       └┘
st   ──────────┘└──────────────────────────┘└──────────────────────────────────┘└──
1559      exact perm_app_left _ perm_app_comm },
id             └───────────┘   └───────────┘
src      └────┘└───────────┘└─┘└───────────┘
typ      └────┘└───────────┘└─┘└───────────┘
doc      └────┘             └─┘             
txt      └────┘             └─┘             
par      └────┘             └─┘             
pid                        └─┘             
st   ───────────────────────────────────────┘└┘
1560    { exact IH₁.trans IH₂ }
id             └───────┘ └─┘
src      └────┘└───────┘   
typ      └────┘└───────┘└─┘
doc      └────┘            
txt      └────┘            
par      └────┘            
pid                       
st   ───────────────────────┘└─
1561  end
st   ──┘
1562  
1563  theorem powerset_aux_perm {l₁ l₂ : list α} (p : l₁ ~ l₂) :
id                                      └──┘        └┘  └┘
src                                     └──┘            
typ                                     └──┘        └┘  └┘
doc                                                     
1564    powerset_aux l₁ ~ powerset_aux l₂ :=
id     └──────────┘ └┘  └──────────┘ └┘
src    └──────────┘     └──────────┘
typ    └──────────┘ └┘  └──────────┘ └┘
doc                    
1565  powerset_aux_perm_powerset_aux'.trans $
id   └─────────────────────────────┘└────┘
src  └─────────────────────────────┘└────┘
typ  └─────────────────────────────┘└────┘
1566  (powerset_aux'_perm p).trans powerset_aux_perm_powerset_aux'.symm
id    └────────────────┘  └───┘  └─────────────────────────────┘└───┘
src   └────────────────┘   └───┘  └─────────────────────────────┘└───┘
typ   └────────────────┘  └───┘  └─────────────────────────────┘└───┘
1567  
1568  def powerset (s : multiset α) : multiset (multiset α) :=
id                     └──────┘     └──────┘  └──────┘ 
src                    └──────┘      └──────┘  └──────┘
typ                    └──────┘     └──────┘  └──────┘ 
doc                    └──────┘      └──────┘  └──────┘
1569  quot.lift_on s
id   └──────────┘ 
src  └──────────┘
typ  └──────────┘ 
1570    (λ l, (powerset_aux l : multiset (multiset α)))
id           └──────────┘    └──────┘  └──────┘ 
src           └──────────┘     └──────┘  └──────┘
typ          └──────────┘    └──────┘  └──────┘ 
doc                            └──────┘  └──────┘
1571    (λ l₁ l₂ h, quot.sound (powerset_aux_perm h))
id        └┘ └┘   └────────┘  └───────────────┘ 
src                └────────┘  └───────────────┘
typ       └┘ └┘   └────────┘  └───────────────┘ 
1572  
1573  theorem powerset_coe (l : list α) :
id                             └──┘ 
src                            └──┘
typ                            └──┘ 
1574    @powerset α l = ((sublists l).map coe : list (multiset α)) :=
id      └──────┘      └──────┘  └─┘  └─┘   └──┘  └──────┘ 
src     └──────┘        └──────┘   └─┘  └─┘   └──┘  └──────┘
typ     └──────┘      └──────┘  └─┘  └─┘   └──┘  └──────┘ 
doc                      └──────┘                    └──────┘
1575  congr_arg coe powerset_aux_eq_map_coe
id   └───────┘ └─┘ └─────────────────────┘
src  └───────┘ └─┘ └─────────────────────┘
typ  └───────┘ └─┘ └─────────────────────┘
1576  
1577  @[simp] theorem powerset_coe' (l : list α) :
id                                      └──┘ 
src                                     └──┘
typ                                     └──┘ 
doc    └──┘
1578    @powerset α l = ((sublists' l).map coe : list (multiset α)) :=
id      └──────┘      └───────┘  └─┘  └─┘   └──┘  └──────┘ 
src     └──────┘        └───────┘   └─┘  └─┘   └──┘  └──────┘
typ     └──────┘      └───────┘  └─┘  └─┘   └──┘  └──────┘ 
doc                      └───────┘                    └──────┘
1579  quot.sound powerset_aux_perm_powerset_aux'
id   └────────┘ └─────────────────────────────┘
src  └────────┘ └─────────────────────────────┘
typ  └────────┘ └─────────────────────────────┘
1580  
1581  @[simp] theorem powerset_zero : @powerset α 0 = 0::0 := rfl
id                                    └──────┘      └┘     └─┘
src                                   └──────┘       └┘     └─┘
typ                                   └──────┘      └┘     └─┘
doc    └──┘                                           └┘
1582  
1583  @[simp] theorem powerset_cons (a : α) (s) :
id                                      
typ                                     
doc    └──┘
1584    powerset (a::s) = powerset s + map (cons a) (powerset s) :=
id     └──────┘  └┘   └──────┘   └─┘  └──┘    └──────┘ 
src    └──────┘   └┘    └──────┘    └─┘  └──┘     └──────┘
typ    └──────┘  └┘   └──────┘   └─┘  └──┘    └──────┘ 
doc               └┘                  └─┘  └──┘
1585  quotient.induction_on s $ λ l, by simp; refl
id   └───────────────────┘      
src  └───────────────────┘             └──┘  └────
typ  └───────────────────┘           └──┘  └────
doc                                    └──┘  └────
txt                                    └──┘  └────
par                                    └──┘  └────
pid                                              
st                                    └───────────
1586  
src  
typ  
doc  
txt  
par  
pid  
st   
1587  @[simp] theorem mem_powerset {s t : multiset α} :
id                                       └──────┘ 
src                                      └──────┘
typ                                      └──────┘ 
doc    └──┘                              └──────┘
1588    s ∈ powerset t ↔ s ≤ t :=
id       └──────┘     
src       └──────┘      
typ      └──────┘     
1589  quotient.induction_on₂ s t $ by simp [subperm, and.comm]
id   └────────────────────┘              └─────┘  └──────┘
src  └────────────────────┘          └────┘└─────┘└┘└──────┘└─
typ  └────────────────────┘        └────┘└─────┘└┘└──────┘└─
doc                                  └────┘└─────┘└┘        └─
txt                                  └────┘       └┘        └─
par                                  └────┘       └┘        └─
pid                                             └┘        
st                                  └─────────────────────────
1590  
src  
typ  
doc  
txt  
par  
pid  
st   
1591  theorem map_single_le_powerset (s : multiset α) :
id                                       └──────┘ 
src                                      └──────┘
typ                                      └──────┘ 
doc                                      └──────┘
1592    s.map (λ a, a::0) ≤ powerset s :=
id     └──┘      └┘    └──────┘ 
src     └──┘        └┘    └──────┘
typ    └──┘      └┘    └──────┘ 
doc     └──┘        └┘
1593  quotient.induction_on s $ λ l, begin
id   └───────────────────┘      
src  └───────────────────┘
typ  └───────────────────┘      
st                                  └─────
1594    simp [powerset_coe],
id           └──────────┘
src    └────┘└──────────┘
typ    └────┘└──────────┘
doc    └────┘            
txt    └────┘            
par    └────┘            
pid                    
st   ────────────────────┘└─
1595    show l.map (coe ∘ list.ret) <+~ (sublists l).map coe,
id          └───┘       └──────┘  └─┘  └──────┘       └─┘
src    └───┘└───┘    └──────┘└┘└─┘ └──────┘ └────┘└─┘
typ    └───┘└───┘    └──────┘└┘└─┘ └──────┘└────┘└─┘
doc    └───┘                  └┘└─┘ └──────┘ └────┘
txt    └───┘                  └┘             └────┘
par    └───┘                  └┘             └────┘
pid    └───┘                  └┘             └────┘
st   ─────────────────────────────────────────────────────┘└─
1596    rw ← list.map_map,
id          └──────────┘
src    └───┘└──────────┘
typ    └───┘└──────────┘
doc    └───┘
txt    └───┘
par    └───┘
pid      └─┘
st   ──────────────────┘└─
1597    exact subperm_of_sublist
id           └────────────────┘
src    └────┘└────────────────┘
typ    └────┘└────────────────┘
doc    └────┘                  
txt    └────┘                  
par    └────┘                  
pid                           
st   ───────────────────────────
1598      (map_sublist_map _ (map_ret_sublist_sublists _))
id        └─────────────┘    └──────────────────────┘
src  ───┘ └─────────────┘└─┘ └──────────────────────┘└───┘
typ  ───┘ └─────────────┘└─┘ └──────────────────────┘└───┘
doc  ───┘                └─┘                         └───┘
txt  ───┘                └─┘                         └───┘
par  ───┘                └─┘                         └───┘
pid  ───┘                └─┘                         └──┘
st   ────────────────────────────────────────────────────┘
1599  end
st   └─┘
1600  
1601  @[simp] theorem card_powerset (s : multiset α) :
id                                      └──────┘ 
src                                     └──────┘
typ                                     └──────┘ 
doc    └──┘                             └──────┘
1602    card (powerset s) = 2 ^ card s :=
id     └──┘  └──────┘       └──┘ 
src    └──┘  └──────┘        └──┘
typ    └──┘  └──────┘       └──┘ 
doc    └──┘                    └──┘
1603  quotient.induction_on s $ by simp
id   └───────────────────┘ 
src  └───────────────────┘        └────
typ  └───────────────────┘       └────
doc                               └────
txt                               └────
par                               └────
pid                                   
st                               └─────
1604  
src  
typ  
doc  
txt  
par  
pid  
st   
1605  /- antidiagonal -/
src  ───────────────────
typ  ───────────────────
doc  ───────────────────
txt  ───────────────────
par  ───────────────────
pid  ───────────────────
st   ───────────────────
1606  
src  
typ  
doc  
txt  
par  
pid  
st   
1607  theorem revzip_powerset_aux {l : list α} ⦃x⦄
id                                    └──┘ 
src                                   └──┘
typ                                   └──┘ 
1608    (h : x ∈ revzip (powerset_aux l)) : x.1 + x.2 = ↑l :=
id            └────┘  └──────────┘            
src            └────┘  └──────────┘               
typ           └────┘  └──────────┘            
1609  begin
st   └─────
1610    rw [revzip, powerset_aux_eq_map_coe, ← map_reverse, zip_map, ← revzip] at h,
id         └────┘  └─────────────────────┘    └─────────┘  └─────┘    └────┘
src    └──┘└────┘└┘└─────────────────────┘└──┘└─────────┘└┘└─────┘└──┘└────┘└────┘
typ    └──┘└────┘└┘└─────────────────────┘└──┘└─────────┘└┘└─────┘└──┘└────┘└────┘
doc    └──┘      └┘                       └──┘           └┘       └──┘      └────┘
txt    └──┘      └┘                       └──┘           └┘       └──┘      └────┘
par    └──┘      └┘                       └──┘           └┘       └──┘      └────┘
pid      └┘      └┘                       └──┘           └┘       └──┘      └───┘
st   ───────────┘└───────────────────────┘└─────────────┘└───────┘└────────┘└───┘└─
1611    simp at h, rcases h with ⟨l₁, l₂, h, rfl, rfl⟩,
id                       
src    └───────┘  └─────┘ └─────────────────────────┘
typ    └───────┘  └─────┘└─────────────────────────┘
doc    └───────┘  └─────┘ └─────────────────────────┘
txt    └───────┘  └─────┘ └─────────────────────────┘
par    └───────┘  └─────┘ └─────────────────────────┘
pid        └──┘         └─────────────────────────┘
st   ──────────┘└───────────────────────────────────┘└─
1612    exact quot.sound (revzip_sublists _ _ _ h)
id           └────────┘  └─────────────┘       
src    └────┘└────────┘ └─────────────┘└─────┘ └┘
typ    └────┘└────────┘ └─────────────┘└─────┘└┘
doc    └────┘                          └─────┘ └┘
txt    └────┘                          └─────┘ └┘
par    └────┘                          └─────┘ └┘
pid                                   └─────┘ 
st   ────────────────────────────────────────────┘
1613  end
st   └─┘
1614  
1615  theorem revzip_powerset_aux' {l : list α} ⦃x⦄
id                                     └──┘ 
src                                    └──┘
typ                                    └──┘ 
1616    (h : x ∈ revzip (powerset_aux' l)) : x.1 + x.2 = ↑l :=
id            └────┘  └───────────┘            
src            └────┘  └───────────┘               
typ           └────┘  └───────────┘            
1617  begin
st   └─────
1618    rw [revzip, powerset_aux', ← map_reverse, zip_map, ← revzip] at h,
id         └────┘  └───────────┘    └─────────┘  └─────┘    └────┘
src    └──┘└────┘└┘└───────────┘└──┘└─────────┘└┘└─────┘└──┘└────┘└────┘
typ    └──┘└────┘└┘└───────────┘└──┘└─────────┘└┘└─────┘└──┘└────┘└────┘
doc    └──┘      └┘             └──┘           └┘       └──┘      └────┘
txt    └──┘      └┘             └──┘           └┘       └──┘      └────┘
par    └──┘      └┘             └──┘           └┘       └──┘      └────┘
pid      └┘      └┘             └──┘           └┘       └──┘      └───┘
st   ───────────┘└─────────────┘└─────────────┘└───────┘└────────┘└───┘└─
1619    simp at h, rcases h with ⟨l₁, l₂, h, rfl, rfl⟩,
id                       
src    └───────┘  └─────┘ └─────────────────────────┘
typ    └───────┘  └─────┘└─────────────────────────┘
doc    └───────┘  └─────┘ └─────────────────────────┘
txt    └───────┘  └─────┘ └─────────────────────────┘
par    └───────┘  └─────┘ └─────────────────────────┘
pid        └──┘         └─────────────────────────┘
st   ──────────┘└───────────────────────────────────┘└─
1620    exact quot.sound (revzip_sublists' _ _ _ h)
id           └────────┘  └──────────────┘       
src    └────┘└────────┘ └──────────────┘└─────┘ └┘
typ    └────┘└────────┘ └──────────────┘└─────┘└┘
doc    └────┘                           └─────┘ └┘
txt    └────┘                           └─────┘ └┘
par    └────┘                           └─────┘ └┘
pid                                    └─────┘ 
st   ─────────────────────────────────────────────┘
1621  end
st   └─┘
1622  
1623  theorem revzip_powerset_aux_lemma [decidable_eq α] (l : list α)
id                                      └──────────┘        └──┘ 
src                                     └──────────┘         └──┘
typ                                     └──────────┘        └──┘ 
1624    {l' : list (multiset α)} (H : ∀ ⦃x : _ × _⦄, x ∈ revzip l' → x.1 + x.2 = ↑l) :
id           └──┘  └──────┘                         └────┘ └┘         
src          └──┘  └──────┘                           └────┘              
typ          └──┘  └──────┘                         └────┘ └┘         
doc                └──────┘
1625    revzip l' = l'.map (λ x, (x, ↑l - x)) :=
id     └────┘ └┘  └┘└──┘          
src    └────┘       └──┘            
typ    └────┘ └┘  └┘└──┘          
1626  begin
st   └─────
1627    have : forall₂ (λ (p : multiset α × multiset α) (s : multiset α), p = (s, ↑l - s))
id            └─────┘         └──────┘                     └──────┘           
src    └─────┘└─────┘  └────┘                  └─────┘└──────┘ └─┘  └┘  └──
typ    └─────┘└─────┘  └────┘└──────┘          └─────┘└──────┘└─┘  └┘ └──
doc    └─────┘         └────┘                   └─────┘└──────┘ └─┘    └┘    └──
txt    └─────┘         └────┘                   └─────┘         └─┘    └┘    └──
par    └─────┘         └────┘                   └─────┘         └─┘    └┘    └──
pid    └───┘└┘         └────┘                   └─────┘         └─┘    └┘    └──
st   ─────────────────────────────────────────────────────────────────────────────────────
1628      (revzip l') ((revzip l').map prod.fst),
id                     └────┘ └┘      └──────┘
src  ───┘         └┘  └────┘  └────┘└──────┘
typ  ───┘         └┘  └────┘└┘└────┘└──────┘
doc  ───┘         └┘          └────┘        
txt  ───┘         └┘          └────┘        
par  ───┘         └┘          └────┘        
pid  ───┘         └┘          └────┘        
st   ─────────────────────────────────────────┘└─
1629    { rw forall₂_map_right_iff,
id          └───────────────────┘
src      └─┘└───────────────────┘
typ      └─┘└───────────────────┘
doc      └─┘
txt      └─┘
par      └─┘
pid        
st   ───┘└──────────────────────┘└─
1630      apply forall₂_same, rintro ⟨s, t⟩ h,
id             └──────────┘
src      └────┘└──────────┘  └─────────────┘
typ      └────┘└──────────┘  └─────────────┘
doc      └────┘              └─────────────┘
txt      └────┘              └─────────────┘
par      └────┘              └─────────────┘
pid                               └───────┘
st   ─────────────────────┘└───────────────┘└─
1631      dsimp, rw [← H h, add_sub_cancel_left] },
id                       └─────────────────┘
src      └───┘  └────┘  └┘└─────────────────┘└┘
typ      └───┘  └────┘└┘└─────────────────┘└┘
doc      └───┘  └────┘  └┘                   └┘
txt      └───┘  └────┘  └┘                   └┘
par      └───┘  └────┘  └┘                   └┘
pid               └──┘  └┘                   
st   ────────┘└─────────┘└───────────────────┘└┘
1632    rw [← forall₂_eq_eq_eq, forall₂_map_right_iff], simpa
id           └──────────────┘  └───────────────────┘
src    └────┘└──────────────┘└┘└───────────────────┘  └────┘
typ    └────┘└──────────────┘└┘└───────────────────┘  └────┘
doc    └────┘                └┘                       └────┘
txt    └────┘                └┘                       └────┘
par    └────┘                └┘                       └────┘
pid      └──┘                └┘                            
st   ───────────────────────┘└─────────────────────┘└───────┘
1633  end
st   └─┘
1634  
1635  theorem revzip_powerset_aux_perm_aux' {l : list α} :
id                                              └──┘ 
src                                             └──┘
typ                                             └──┘ 
1636    revzip (powerset_aux l) ~ revzip (powerset_aux' l) :=
id     └────┘  └──────────┘    └────┘  └───────────┘ 
src    └────┘  └──────────┘     └────┘  └───────────┘
typ    └────┘  └──────────┘    └────┘  └───────────┘ 
doc                            
1637  begin
st   └─────
1638    haveI := classical.dec_eq α,
id              └──────────────┘ 
src    └───────┘└──────────────┘
typ    └───────┘└──────────────┘
doc    └───────┘                
txt    └───────┘                
par    └───────┘                
pid         └─┘                
st   ────────────────────────────┘└─
1639    rw [revzip_powerset_aux_lemma l revzip_powerset_aux,
id         └───────────────────────┘  └─────────────────┘
src    └──┘└───────────────────────┘ └─────────────────┘└─
typ    └──┘└───────────────────────┘└─────────────────┘└─
doc    └──┘                                             └─
txt    └──┘                                             └─
par    └──┘                                             └─
pid      └┘                                             └─
st   ────────────────────────────────────────────────────┘└─
1640        revzip_powerset_aux_lemma l revzip_powerset_aux'],
id         └───────────────────────┘  └──────────────────┘
src  ─────┘└───────────────────────┘ └──────────────────┘
typ  ─────┘└───────────────────────┘└──────────────────┘
doc  ─────┘                                              
txt  ─────┘                                              
par  ─────┘                                              
pid  ─────┘                                              
st   ─────────────────────────────────────────────────────┘└──
1641    exact perm_map _ powerset_aux_perm_powerset_aux',
id           └──────┘   └─────────────────────────────┘
src    └────┘└──────┘└─┘└─────────────────────────────┘
typ    └────┘└──────┘└─┘└─────────────────────────────┘
doc    └────┘        └─┘
txt    └────┘        └─┘
par    └────┘        └─┘
pid                 └─┘
st   ─────────────────────────────────────────────────┘└─
1642  end
st   ──┘
1643  
1644  theorem revzip_powerset_aux_perm {l₁ l₂ : list α} (p : l₁ ~ l₂) :
id                                             └──┘        └┘  └┘
src                                            └──┘            
typ                                            └──┘        └┘  └┘
doc                                                            
1645    revzip (powerset_aux l₁) ~ revzip (powerset_aux l₂) :=
id     └────┘  └──────────┘ └┘   └────┘  └──────────┘ └┘
src    └────┘  └──────────┘      └────┘  └──────────┘
typ    └────┘  └──────────┘ └┘   └────┘  └──────────┘ └┘
doc                             
1646  begin
st   └─────
1647    haveI := classical.dec_eq α,
id              └──────────────┘ 
src    └───────┘└──────────────┘
typ    └───────┘└──────────────┘
doc    └───────┘                
txt    └───────┘                
par    └───────┘                
pid         └─┘                
st   ────────────────────────────┘└─
1648    simp [λ l:list α, revzip_powerset_aux_lemma l revzip_powerset_aux, coe_eq_coe.2 p],
id               └──┘   └───────────────────────┘   └─────────────────┘  └────────┘   
src    └────┘ └─┘└──┘ └┘└───────────────────────┘ └─────────────────┘└┘└────────┘└─┘ 
typ    └────┘ └─┘└──┘└┘└───────────────────────┘ └─────────────────┘└┘└────────┘└─┘
doc    └────┘ └─┘     └┘                                             └┘          └─┘ 
txt    └────┘ └─┘     └┘                                             └┘          └─┘ 
par    └────┘ └─┘     └┘                                             └┘          └─┘ 
pid         └─┘     └┘                                             └┘          └─┘ 
st   ───────────────────────────────────────────────────────────────────────────────────┘└─
1649    exact perm_map _ (powerset_aux_perm p)
id           └──────┘    └───────────────┘ 
src    └────┘└──────┘└─┘ └───────────────┘ └┘
typ    └────┘└──────┘└─┘ └───────────────┘└┘
doc    └────┘        └─┘                   └┘
txt    └────┘        └─┘                   └┘
par    └────┘        └─┘                   └┘
pid                 └─┘                   
st   ────────────────────────────────────────┘
1650  end
st   └─┘
1651  
1652  /-- The antidiagonal of a multiset `s` consists of all pairs `(t₁, t₂)`
1653      such that `t₁ + t₂ = s`. These pairs are counted with multiplicities. -/
1654  def antidiagonal (s : multiset α) : multiset (multiset α × multiset α) :=
id                         └──────┘     └──────┘  └──────┘   └──────┘ 
src                        └──────┘      └──────┘  └──────┘    └──────┘
typ                        └──────┘     └──────┘  └──────┘   └──────┘ 
doc                        └──────┘      └──────┘  └──────┘     └──────┘
1655  quot.lift_on s
id   └──────────┘ 
src  └──────────┘
typ  └──────────┘ 
1656    (λ l, (revzip (powerset_aux l) : multiset (multiset α × multiset α)))
id           └────┘  └──────────┘     └──────┘  └──────┘   └──────┘ 
src           └────┘  └──────────┘      └──────┘  └──────┘    └──────┘
typ          └────┘  └──────────┘     └──────┘  └──────┘   └──────┘ 
doc                                     └──────┘  └──────┘     └──────┘
1657    (λ l₁ l₂ h, quot.sound (revzip_powerset_aux_perm h))
id        └┘ └┘   └────────┘  └──────────────────────┘ 
src                └────────┘  └──────────────────────┘
typ       └┘ └┘   └────────┘  └──────────────────────┘ 
1658  
1659  theorem antidiagonal_coe (l : list α) :
id                                 └──┘ 
src                                └──┘
typ                                └──┘ 
1660    @antidiagonal α l = revzip (powerset_aux l) := rfl
id      └──────────┘    └────┘  └──────────┘      └─┘
src     └──────────┘      └────┘  └──────────┘       └─┘
typ     └──────────┘    └────┘  └──────────┘      └─┘
doc     └──────────┘
1661  
1662  @[simp] theorem antidiagonal_coe' (l : list α) :
id                                          └──┘ 
src                                         └──┘
typ                                         └──┘ 
doc    └──┘
1663    @antidiagonal α l = revzip (powerset_aux' l) :=
id      └──────────┘    └────┘  └───────────┘ 
src     └──────────┘      └────┘  └───────────┘
typ     └──────────┘    └────┘  └───────────┘ 
doc     └──────────┘
1664  quot.sound revzip_powerset_aux_perm_aux'
id   └────────┘ └───────────────────────────┘
src  └────────┘ └───────────────────────────┘
typ  └────────┘ └───────────────────────────┘
1665  
1666  /-- A pair `(t₁, t₂)` of multisets is contained in `antidiagonal s`
1667      if and only if `t₁ + t₂ = s`. -/
1668  @[simp] theorem mem_antidiagonal {s : multiset α} {x : multiset α × multiset α} :
id                                         └──────┘        └──────┘   └──────┘ 
src                                        └──────┘         └──────┘    └──────┘
typ                                        └──────┘        └──────┘   └──────┘ 
doc    └──┘                                └──────┘         └──────┘     └──────┘
1669    x ∈ antidiagonal s ↔ x.1 + x.2 = s :=
id       └──────────┘         
src       └──────────┘           
typ      └──────────┘         
doc        └──────────┘
1670  quotient.induction_on s $ λ l, begin
id   └───────────────────┘      
src  └───────────────────┘
typ  └───────────────────┘      
st                                  └─────
1671    simp [antidiagonal_coe], refine ⟨λ h, revzip_powerset_aux h, λ h, _⟩,
id           └──────────────┘                └─────────────────┘
src    └────┘└──────────────┘  └─────┘  └──┘└─────────────────┘ └┘ └────┘
typ    └────┘└──────────────┘  └─────┘  └──┘└─────────────────┘ └┘ └────┘
doc    └────┘                  └─────┘  └──┘                    └┘ └────┘
txt    └────┘                  └─────┘  └──┘                    └┘ └────┘
par    └────┘                  └─────┘  └──┘                    └┘ └────┘
pid                                  └──┘                    └┘ └────┘
st   ────────────────────────┘└───────────────────────────────────────────┘└─
1672    haveI := classical.dec_eq α,
id              └──────────────┘ 
src    └───────┘└──────────────┘
typ    └───────┘└──────────────┘
doc    └───────┘                
txt    └───────┘                
par    └───────┘                
pid         └─┘                
st   ────────────────────────────┘└─
1673    simp [revzip_powerset_aux_lemma l revzip_powerset_aux, h.symm],
id           └───────────────────────┘  └─────────────────┘
src    └────┘└───────────────────────┘ └─────────────────┘└┘      
typ    └────┘└───────────────────────┘└─────────────────┘└┘└────┘
doc    └────┘                                             └┘      
txt    └────┘                                             └┘      
par    └────┘                                             └┘      
pid                                                     └┘      
st   ───────────────────────────────────────────────────────────────┘└─
1674    cases x with x₁ x₂,
id           
src    └────┘ └─────────┘
typ    └────┘└─────────┘
doc    └────┘ └─────────┘
txt    └────┘ └─────────┘
par    └────┘ └─────────┘
pid          └─────────┘
st   ───────────────────┘└─
1675    exact ⟨_, le_add_right _ _, by rw add_sub_cancel_left _ _⟩
id               └──────────┘            └─────────────────┘
src    └────┘ └─┘└──────────┘└────┘  └─┘└─────────────────┘└──┘└┘
typ    └────┘ └─┘└──────────┘└────┘  └─┘└─────────────────┘└──┘└┘
doc    └────┘ └─┘            └────┘  └─┘                   └──┘└┘
txt    └────┘ └─┘            └────┘  └─┘                   └──┘└┘
par    └────┘ └─┘            └────┘  └─┘                   └──┘└┘
pid          └─┘            └────┘  └──┘                   └───┘
st   ───────────────────────────────┘└─────────────────────────┘└┘
1676  end
st   └─┘
1677  
1678  @[simp] theorem antidiagonal_map_fst (s : multiset α) :
id                                             └──────┘ 
src                                            └──────┘
typ                                            └──────┘ 
doc    └──┘                                    └──────┘
1679    (antidiagonal s).map prod.fst = powerset s :=
id      └──────────┘  └─┘  └──────┘  └──────┘ 
src     └──────────┘   └─┘  └──────┘  └──────┘
typ     └──────────┘  └─┘  └──────┘  └──────┘ 
doc     └──────────┘   └─┘
1680  quotient.induction_on s $ λ l,
id   └───────────────────┘      
src  └───────────────────┘
typ  └───────────────────┘      
1681  by simp [powerset_aux']
id            └───────────┘
src     └────┘└───────────┘└─
typ     └────┘└───────────┘└─
doc     └────┘             └─
txt     └────┘             └─
par     └────┘             └─
pid                      
st     └─────────────────────
1682  
src  
typ  
doc  
txt  
par  
pid  
st   
1683  @[simp] theorem antidiagonal_map_snd (s : multiset α) :
id                                             └──────┘ 
src                                            └──────┘
typ                                            └──────┘ 
doc    └──┘                                    └──────┘
1684    (antidiagonal s).map prod.snd = powerset s :=
id      └──────────┘  └─┘  └──────┘  └──────┘ 
src     └──────────┘   └─┘  └──────┘  └──────┘
typ     └──────────┘  └─┘  └──────┘  └──────┘ 
doc     └──────────┘   └─┘
1685  quotient.induction_on s $ λ l,
id   └───────────────────┘      
src  └───────────────────┘
typ  └───────────────────┘      
1686  by simp [powerset_aux']
id            └───────────┘
src     └────┘└───────────┘└─
typ     └────┘└───────────┘└─
doc     └────┘             └─
txt     └────┘             └─
par     └────┘             └─
pid                      
st     └─────────────────────
1687  
src  
typ  
doc  
txt  
par  
pid  
st   
1688  @[simp] theorem antidiagonal_zero : @antidiagonal α 0 = (0, 0)::0 := rfl
id                                        └──────────┘          └┘     └─┘
src                                       └──────────┘           └┘     └─┘
typ                                       └──────────┘          └┘     └─┘
doc    └──┘                               └──────────┘             └┘
1689  
1690  @[simp] theorem antidiagonal_cons (a : α) (s) : antidiagonal (a::s) =
id                                                  └──────────┘  └┘  
src                                                  └──────────┘   └┘   
typ                                                 └──────────┘  └┘  
doc    └──┘                                          └──────────┘   └┘
1691    map (prod.map id (cons a)) (antidiagonal s) +
id     └─┘  └──────┘ └┘  └──┘     └──────────┘   
src    └─┘  └──────┘ └┘  └──┘      └──────────┘    
typ    └─┘  └──────┘ └┘  └──┘     └──────────┘   
doc    └─┘               └──┘      └──────────┘
1692    map (prod.map (cons a) id) (antidiagonal s) :=
id     └─┘  └──────┘  └──┘   └┘   └──────────┘ 
src    └─┘  └──────┘  └──┘    └┘   └──────────┘
typ    └─┘  └──────┘  └──┘   └┘   └──────────┘ 
doc    └─┘            └──┘         └──────────┘
1693  quotient.induction_on s $ λ l, begin
id   └───────────────────┘      
src  └───────────────────┘
typ  └───────────────────┘      
st                                  └─────
1694    simp [revzip, reverse_append],
id           └────┘  └────────────┘
src    └────┘└────┘└┘└────────────┘
typ    └────┘└────┘└┘└────────────┘
doc    └────┘      └┘              
txt    └────┘      └┘              
par    └────┘      └┘              
pid              └┘              
st   ──────────────────────────────┘└─
1695    rw [← zip_map, ← zip_map, zip_append, (_ : _++_=_)],
id           └─────┘    └─────┘  └────────┘        └┘ 
src    └────┘└─────┘└──┘└─────┘└┘└────────┘└┘ └───┘└┘└─┘
typ    └────┘└─────┘└──┘└─────┘└┘└────────┘└┘ └───┘└┘└─┘
doc    └────┘       └──┘       └┘          └┘ └───┘   └─┘
txt    └────┘       └──┘       └┘          └┘ └───┘   └─┘
par    └────┘       └──┘       └┘          └┘ └───┘   └─┘
pid      └──┘       └──┘       └┘          └┘ └───┘   └─┘
st   ──────────────┘└─────────┘└──────────┘└────────────┘└──
1696    {congr; simp}, {simp}
src     └───┘  └──┘    └──┘
typ     └───┘  └──┘    └──┘
doc            └──┘    └──┘
txt     └───┘  └──┘    └──┘
par     └───┘  └──┘    └──┘
st   ─────────────┘└┘└────┘└─
1697  end
st   ──┘
1698  
1699  @[simp] theorem card_antidiagonal (s : multiset α) :
id                                          └──────┘ 
src                                         └──────┘
typ                                         └──────┘ 
doc    └──┘                                 └──────┘
1700    card (antidiagonal s) = 2 ^ card s :=
id     └──┘  └──────────┘       └──┘ 
src    └──┘  └──────────┘        └──┘
typ    └──┘  └──────────┘       └──┘ 
doc    └──┘  └──────────┘          └──┘
1701  by have := card_powerset s;
id              └───────────┘ 
src     └──────┘└───────────┘
typ     └──────┘└───────────┘
doc     └──────┘             
txt     └──────┘             
par     └──────┘             
pid     └───┘└─┘             
st     └─────────────────────────
1702     rwa [← antidiagonal_map_fst, card_map] at this
id             └──────────────────┘  └──────┘
src     └─────┘└──────────────────┘└┘└──────┘└─────────
typ     └─────┘└──────────────────┘└┘└──────┘└─────────
doc     └─────┘                    └┘        └─────────
txt     └─────┘                    └┘        └─────────
par     └─────┘                    └┘        └─────────
pid        └──┘                    └┘        └──────┘
st   ───────┘└────────────────────┘└────────┘└────────
1703  
src  
typ  
doc  
txt  
par  
pid  
st   
1704  lemma prod_map_add [comm_semiring β] {s : multiset α} {f g : α → β} :
id                       └───────────┘        └──────┘             
src                      └───────────┘         └──────┘
typ                      └───────────┘        └──────┘             
doc                                            └──────┘
1705    prod (s.map (λa, f a + g a)) =
id     └──┘  └──┘            
src    └──┘   └──┘                 
typ    └──┘  └──┘            
doc    └──┘   └──┘
1706    sum ((antidiagonal s).map (λp, (p.1.map f).prod * (p.2.map g).prod)) :=
id     └─┘   └──────────┘  └─┘        └─┘   └──┘     └─┘   └──┘
src    └─┘   └──────────┘   └─┘          └─┘    └──┘      └─┘    └──┘
typ    └─┘   └──────────┘  └─┘        └─┘   └──┘     └─┘   └──┘
doc          └──────────┘   └─┘           └─┘    └──┘        └─┘    └──┘
1707  begin
st   └─────
1708    refine s.induction_on _ _,
id            └────────────┘
src    └─────┘└────────────┘└──┘
typ    └─────┘└────────────┘└──┘
doc    └─────┘              └──┘
txt    └─────┘              └──┘
par    └─────┘              └──┘
pid                        └──┘
st   ──────────────────────────┘└─
1709    { simp },
src      └───┘
typ      └───┘
doc      └───┘
txt      └───┘
par      └───┘
pid          
st   ───┘└───┘└┘
1710    { assume a s ih, simp [ih, add_mul, mul_comm, mul_left_comm, mul_assoc, sum_map_mul_left.symm] },
id                            └┘  └─────┘  └──────┘  └───────────┘  └───────┘
src      └───────────┘  └────┘  └┘└─────┘└┘└──────┘└┘└───────────┘└┘└───────┘└┘                     └┘
typ      └───────────┘  └────┘└┘└┘└─────┘└┘└──────┘└┘└───────────┘└┘└───────┘└┘└───────────────────┘└┘
doc      └───────────┘  └────┘  └┘       └┘        └┘             └┘         └┘                     └┘
txt      └───────────┘  └────┘  └┘       └┘        └┘             └┘         └┘                     └┘
par      └───────────┘  └────┘  └┘       └┘        └┘             └┘         └┘                     └┘
pid      └───────────┘        └┘       └┘        └┘             └┘         └┘                     
st   ────────────────┘└──────────────────────────────────────────────────────────────────────────────┘└──
1711  end
st   ──┘
1712  
1713  /- powerset_len -/
1714  
1715  def powerset_len_aux (n : ℕ) (l : list α) : list (multiset α) :=
id                                    └──┘     └──┘  └──────┘ 
src                                   └──┘      └──┘  └──────┘
typ                                   └──┘     └──┘  └──────┘ 
doc                                                    └──────┘
1716  sublists_len_aux n l coe []
id   └──────────────┘   └─┘ └┘
src  └──────────────┘     └─┘ └┘
typ  └──────────────┘   └─┘ └┘
1717  
1718  theorem powerset_len_aux_eq_map_coe {n} {l : list α} :
id                                                └──┘ 
src                                               └──┘
typ                                               └──┘ 
1719    powerset_len_aux n l = (sublists_len n l).map coe :=
id     └──────────────┘     └──────────┘   └─┘  └─┘
src    └──────────────┘       └──────────┘     └─┘  └─┘
typ    └──────────────┘     └──────────┘   └─┘  └─┘
1720  by rw [powerset_len_aux, sublists_len_aux_eq, append_nil]
id          └──────────────┘  └─────────────────┘  └────────┘
src     └──┘└──────────────┘└┘└─────────────────┘└┘└────────┘└─
typ     └──┘└──────────────┘└┘└─────────────────┘└┘└────────┘└─
doc     └──┘                └┘                   └┘          └─
txt     └──┘                └┘                   └┘          └─
par     └──┘                └┘                   └┘          └─
pid       └┘                └┘                   └┘          
st     └───────────────────┘└───────────────────┘└──────────┘
1721  
src  
typ  
doc  
txt  
par  
pid  
st   
1722  @[simp] theorem mem_powerset_len_aux {n} {l : list α} {s} :
id                                                 └──┘ 
src                                                └──┘
typ                                                └──┘ 
doc    └──┘
1723    s ∈ powerset_len_aux n l ↔ s ≤ ↑l ∧ card s = n :=
id       └──────────────┘        └──┘   
src       └──────────────┘            └──┘   
typ      └──────────────┘        └──┘   
doc                                        └──┘
1724  quotient.induction_on s $
id   └───────────────────┘ 
src  └───────────────────┘
typ  └───────────────────┘ 
1725  by simp [powerset_len_aux_eq_map_coe, subperm]; exact
id            └─────────────────────────┘  └─────┘
src     └────┘└─────────────────────────┘└┘└─────┘  └─────
typ     └────┘└─────────────────────────┘└┘└─────┘  └─────
doc     └────┘                           └┘└─────┘  └─────
txt     └────┘                           └┘         └─────
par     └────┘                           └┘         └─────
pid                                    └┘              
st     └───────────────────────────────────────────────────
1726    λ l₁, ⟨λ ⟨l₂, ⟨s, e⟩, p⟩, ⟨⟨_, p, s⟩, (perm_length p.symm).trans e⟩,
id                                                      └───┘
src  ─┘ └───┘  └┘  └┘  └┘ └─┘ └─┘  └─┘ └┘ └─┘             └───┘└──────┘ └──
typ  ─┘ └───┘  └┘  └┘ └┘└─┘└─┘  └─┘ └┘ └─┘             └───┘└──────┘ └──
doc  ─┘ └───┘  └┘  └┘  └┘ └─┘ └─┘  └─┘ └┘ └─┘                  └──────┘ └──
txt  ─┘ └───┘  └┘  └┘  └┘ └─┘ └─┘  └─┘ └┘ └─┘                  └──────┘ └──
par  ─┘ └───┘  └┘  └┘  └┘ └─┘ └─┘  └─┘ └┘ └─┘                  └──────┘ └──
pid  ─┘ └───┘  └┘  └┘  └┘ └─┘ └─┘  └─┘ └┘ └─┘                  └──────┘ └──
st   ───────────────────────────────────────────────────────────────────────
1727      λ ⟨⟨l₂, p, s⟩, e⟩, ⟨_, ⟨s, (perm_length p).trans e⟩, p⟩⟩
id                                └─────────┘
src  ───┘ └┘   └┘ └┘ └─┘ └─┘ └─┘  └┘ └─────────┘ └──────┘ └─┘ └──
typ  ───┘ └┘   └┘└┘└─┘└─┘ └─┘  └┘ └─────────┘ └──────┘ └─┘ └──
doc  ───┘ └┘   └┘ └┘ └─┘ └─┘ └─┘  └┘             └──────┘ └─┘ └──
txt  ───┘ └┘   └┘ └┘ └─┘ └─┘ └─┘  └┘             └──────┘ └─┘ └──
par  ───┘ └┘   └┘ └┘ └─┘ └─┘ └─┘  └┘             └──────┘ └─┘ └──
pid  ───┘ └┘   └┘ └┘ └─┘ └─┘ └─┘  └┘             └──────┘ └─┘ └┘
st   ─────────────────────────────────────────────────────────────
1728  
src  
typ  
doc  
txt  
par  
pid  
st   
1729  @[simp] theorem powerset_len_aux_zero (l : list α) :
id                                              └──┘ 
src                                             └──┘
typ                                             └──┘ 
doc    └──┘
1730    powerset_len_aux 0 l = [0] :=
id     └──────────────┘      
src    └──────────────┘       
typ    └──────────────┘      
1731  by simp [powerset_len_aux_eq_map_coe]
id            └─────────────────────────┘
src     └────┘└─────────────────────────┘└─
typ     └────┘└─────────────────────────┘└─
doc     └────┘                           └─
txt     └────┘                           └─
par     └────┘                           └─
pid                                    
st     └───────────────────────────────────
1732  
src  
typ  
doc  
txt  
par  
pid  
st   
1733  @[simp] theorem powerset_len_aux_nil (n : ℕ) :
id                                             
src                                            
typ                                            
doc    └──┘
1734    powerset_len_aux (n+1) (@nil α) = [] := rfl
id     └──────────────┘       └─┘    └┘    └─┘
src    └──────────────┘        └─┘     └┘    └─┘
typ    └──────────────┘       └─┘    └┘    └─┘
1735  
1736  @[simp] theorem powerset_len_aux_cons (n : ℕ) (a : α) (l : list α) :
id                                                            └──┘ 
src                                                            └──┘
typ                                                           └──┘ 
doc    └──┘
1737    powerset_len_aux (n+1) (a::l) =
id     └──────────────┘      └┘  
src    └──────────────┘        └┘   
typ    └──────────────┘      └┘  
1738    powerset_len_aux (n+1) l ++ list.map (cons a) (powerset_len_aux n l) :=
id     └──────────────┘      └┘ └──────┘  └──┘    └──────────────┘  
src    └──────────────┘        └┘ └──────┘  └──┘     └──────────────┘
typ    └──────────────┘      └┘ └──────┘  └──┘    └──────────────┘  
doc                                          └──┘
1739  by simp [powerset_len_aux_eq_map_coe]; refl
id            └─────────────────────────┘
src     └────┘└─────────────────────────┘  └────
typ     └────┘└─────────────────────────┘  └────
doc     └────┘                             └────
txt     └────┘                             └────
par     └────┘                             └────
pid                                          
st     └─────────────────────────────────────────
1740  
src  
typ  
doc  
txt  
par  
pid  
st   
1741  theorem powerset_len_aux_perm {n} {l₁ l₂ : list α} (p : l₁ ~ l₂) :
id                                              └──┘        └┘  └┘
src                                             └──┘            
typ                                             └──┘        └┘  └┘
doc                                                             
1742    powerset_len_aux n l₁ ~ powerset_len_aux n l₂ :=
id     └──────────────┘  └┘  └──────────────┘  └┘
src    └──────────────┘       └──────────────┘
typ    └──────────────┘  └┘  └──────────────┘  └┘
doc                          
1743  begin
st   └─────
1744    induction n with n IHn generalizing l₁ l₂, {simp},
id               
src    └────────┘ └────────────────────────────┘   └──┘
typ    └────────┘└────────────────────────────┘   └──┘
doc    └────────┘ └────────────────────────────┘   └──┘
txt    └────────┘ └────────────────────────────┘   └──┘
par    └────────┘ └────────────────────────────┘   └──┘
pid              └────────┘└─────────────────┘
st   ──────────────────────────────────────────┘└─────┘└┘
1745    induction p with a l₁ l₂ p IH a b l l₁ l₂ l₃ p₁ p₂ IH₁ IH₂, {refl},
id               
src    └────────┘ └─────────────────────────────────────────────┘   └──┘
typ    └────────┘└─────────────────────────────────────────────┘   └──┘
doc    └────────┘ └─────────────────────────────────────────────┘   └──┘
txt    └────────┘ └─────────────────────────────────────────────┘   └──┘
par    └────────┘ └─────────────────────────────────────────────┘   └──┘
pid              └────────────────────────────────────────────┘
st   ───────────────────────────────────────────────────────────┘└─────┘└┘
1746    { simp, exact perm_app IH (perm_map _ (IHn p)) },
id                   └──────┘ └┘  └──────┘    └─┘ 
src      └──┘  └────┘└──────┘   └──────┘└─┘     └─┘
typ      └──┘  └────┘└──────┘└┘ └──────┘└─┘ └─┘└─┘
doc      └──┘  └────┘                   └─┘     └─┘
txt      └──┘  └────┘                   └─┘     └─┘
par      └──┘  └────┘                   └─┘     └─┘
pid                                    └─┘     └┘
st   ───┘└──┘└───────────────────────────────────────┘└┘
1747    { simp, apply perm_app_right,
id                   └────────────┘
src      └──┘  └────┘└────────────┘
typ      └──┘  └────┘└────────────┘
doc      └──┘  └────┘
txt      └──┘  └────┘
par      └──┘  └────┘
pid                 
st   ───┘└──┘└────────────────────┘└─
1748      cases n, {simp, apply perm.swap},
id                            └───────┘
src      └────┘    └──┘  └────┘└───────┘
typ      └────┘   └──┘  └────┘└───────┘
doc      └────┘    └──┘  └────┘
txt      └────┘    └──┘  └────┘
par      └────┘    └──┘  └────┘
pid                          
st   ──────────┘└─────┘└───────────────┘└┘
1749      simp,
src      └──┘
typ      └──┘
doc      └──┘
txt      └──┘
par      └──┘
st   ───────┘└─
1750      rw [← append_assoc, ← append_assoc,
id             └──────────┘    └──────────┘
src      └────┘└──────────┘└──┘└──────────┘└─
typ      └────┘└──────────┘└──┘└──────────┘└─
doc      └────┘            └──┘            └─
txt      └────┘            └──┘            └─
par      └────┘            └──┘            └─
pid        └──┘            └──┘            └─
st   ─────────────────────┘└──────────────┘└─
1751          (by funext s; simp [cons_swap] : cons b ∘ cons a = cons a ∘ cons b)],
id                               └───────┘                            └──┘ 
src  ───────┘   └──────┘└┘└────┘└───────┘└┘└┘                └──┘ └┘
typ  ───────┘   └──────┘└┘└────┘└───────┘└┘└┘               └──┘└┘
doc  ───────┘   └──────┘└┘└────┘         └┘└┘                  └──┘ └┘
txt  ───────┘   └──────┘└┘└────┘         └┘└┘                       └┘
par  ───────┘   └──────┘└┘└────┘         └┘└┘                       └┘
pid  ───────┘   └───────────────┘         └──┘                       └┘
st   ──────────┘└──────────────────────────┘└──────────────────────────────────┘└─
1752      exact perm_app_left _ perm_app_comm },
id             └───────────┘   └───────────┘
src      └────┘└───────────┘└─┘└───────────┘
typ      └────┘└───────────┘└─┘└───────────┘
doc      └────┘             └─┘             
txt      └────┘             └─┘             
par      └────┘             └─┘             
pid                        └─┘             
st   ───────────────────────────────────────┘└┘
1753    { exact IH₁.trans IH₂ }
id             └───────┘ └─┘
src      └────┘└───────┘   
typ      └────┘└───────┘└─┘
doc      └────┘            
txt      └────┘            
par      └────┘            
pid                       
st   ───────────────────────┘└─
1754  end
st   ──┘
1755  
1756  def powerset_len (n : ℕ) (s : multiset α) : multiset (multiset α) :=
id                                └──────┘     └──────┘  └──────┘ 
src                               └──────┘      └──────┘  └──────┘
typ                               └──────┘     └──────┘  └──────┘ 
doc                                └──────┘      └──────┘  └──────┘
1757  quot.lift_on s
id   └──────────┘ 
src  └──────────┘
typ  └──────────┘ 
1758    (λ l, (powerset_len_aux n l : multiset (multiset α)))
id           └──────────────┘     └──────┘  └──────┘ 
src           └──────────────┘       └──────┘  └──────┘
typ          └──────────────┘     └──────┘  └──────┘ 
doc                                  └──────┘  └──────┘
1759    (λ l₁ l₂ h, quot.sound (powerset_len_aux_perm h))
id        └┘ └┘   └────────┘  └───────────────────┘ 
src                └────────┘  └───────────────────┘
typ       └┘ └┘   └────────┘  └───────────────────┘ 
1760  
1761  theorem powerset_len_coe' (n) (l : list α) :
id                                      └──┘ 
src                                     └──┘
typ                                     └──┘ 
1762    @powerset_len α n l = powerset_len_aux n l := rfl
id      └──────────┘     └──────────────┘      └─┘
src     └──────────┘        └──────────────┘        └─┘
typ     └──────────┘     └──────────────┘      └─┘
1763  
1764  theorem powerset_len_coe (n) (l : list α) :
id                                     └──┘ 
src                                    └──┘
typ                                    └──┘ 
1765    @powerset_len α n l = ((sublists_len n l).map coe : list (multiset α)) :=
id      └──────────┘       └──────────┘   └─┘  └─┘   └──┘  └──────┘ 
src     └──────────┘          └──────────┘     └─┘  └─┘   └──┘  └──────┘
typ     └──────────┘       └──────────┘   └─┘  └─┘   └──┘  └──────┘ 
doc                                                              └──────┘
1766  congr_arg coe powerset_len_aux_eq_map_coe
id   └───────┘ └─┘ └─────────────────────────┘
src  └───────┘ └─┘ └─────────────────────────┘
typ  └───────┘ └─┘ └─────────────────────────┘
1767  
1768  @[simp] theorem powerset_len_zero_left (s : multiset α) :
id                                               └──────┘ 
src                                              └──────┘
typ                                              └──────┘ 
doc    └──┘                                      └──────┘
1769    powerset_len 0 s = 0::0 :=
id     └──────────┘      └┘
src    └──────────┘       └┘
typ    └──────────┘      └┘
doc                        └┘
1770  quotient.induction_on s $ λ l, by simp [powerset_len_coe']; refl
id   └───────────────────┘                 └───────────────┘
src  └───────────────────┘             └────┘└───────────────┘  └────
typ  └───────────────────┘           └────┘└───────────────┘  └────
doc                                    └────┘                   └────
txt                                    └────┘                   └────
par                                    └────┘                   └────
pid                                                               
st                                    └───────────────────────────────
1771  
src  
typ  
doc  
txt  
par  
pid  
st   
1772  @[simp] theorem powerset_len_zero_right (n : ℕ) :
id                                                
src                                               
typ                                               
doc    └──┘
1773    @powerset_len α (n + 1) 0 = 0 := rfl
id      └──────────┘                └─┘
src     └──────────┘                  └─┘
typ     └──────────┘                └─┘
1774  
1775  @[simp] theorem powerset_len_cons (n : ℕ) (a : α) (s) :
id                                                 
src                                         
typ                                                
doc    └──┘
1776    powerset_len (n + 1) (a::s) =
id     └──────────┘        └┘  
src    └──────────┘          └┘   
typ    └──────────┘        └┘  
doc                           └┘
1777    powerset_len (n + 1) s + map (cons a) (powerset_len n s) :=
id     └──────────┘         └─┘  └──┘    └──────────┘  
src    └──────────┘           └─┘  └──┘     └──────────┘
typ    └──────────┘         └─┘  └──┘    └──────────┘  
doc                             └─┘  └──┘
1778  quotient.induction_on s $ λ l, by simp [powerset_len_coe']; refl
id   └───────────────────┘                 └───────────────┘
src  └───────────────────┘             └────┘└───────────────┘  └────
typ  └───────────────────┘           └────┘└───────────────┘  └────
doc                                    └────┘                   └────
txt                                    └────┘                   └────
par                                    └────┘                   └────
pid                                                               
st                                    └───────────────────────────────
1779  
src  
typ  
doc  
txt  
par  
pid  
st   
1780  @[simp] theorem mem_powerset_len {n : ℕ} {s t : multiset α} :
id                                                  └──────┘ 
src                                                 └──────┘
typ                                                 └──────┘ 
doc    └──┘                                          └──────┘
1781    s ∈ powerset_len n t ↔ s ≤ t ∧ card s = n :=
id       └──────────┘        └──┘   
src       └──────────┘            └──┘   
typ      └──────────┘        └──┘   
doc                                   └──┘
1782  quotient.induction_on t $ λ l, by simp [powerset_len_coe']
id   └───────────────────┘                 └───────────────┘
src  └───────────────────┘             └────┘└───────────────┘└─
typ  └───────────────────┘           └────┘└───────────────┘└─
doc                                    └────┘                 └─
txt                                    └────┘                 └─
par                                    └────┘                 └─
pid                                                         
st                                    └─────────────────────────
1783  
src  
typ  
doc  
txt  
par  
pid  
st   
1784  @[simp] theorem card_powerset_len (n : ℕ) (s : multiset α) :
id                                                 └──────┘ 
src                                                └──────┘
typ                                                └──────┘ 
doc    └──┘                                         └──────┘
1785    card (powerset_len n s) = nat.choose (card s) n :=
id     └──┘  └──────────┘     └────────┘  └──┘   
src    └──┘  └──────────┘       └────────┘  └──┘
typ    └──┘  └──────────┘     └────────┘  └──┘   
doc    └──┘                      └────────┘  └──┘
1786  quotient.induction_on s $ by simp [powerset_len_coe]
id   └───────────────────┘             └──────────────┘
src  └───────────────────┘        └────┘└──────────────┘└─
typ  └───────────────────┘       └────┘└──────────────┘└─
doc                               └────┘                └─
txt                               └────┘                └─
par                               └────┘                └─
pid                                                   
st                               └────────────────────────
1787  
src  
typ  
doc  
txt  
par  
pid  
st   
1788  theorem powerset_len_le_powerset (n : ℕ) (s : multiset α) :
id                                                └──────┘ 
src                                               └──────┘
typ                                               └──────┘ 
doc                                                └──────┘
1789    powerset_len n s ≤ powerset s :=
id     └──────────┘    └──────┘ 
src    └──────────┘      └──────┘
typ    └──────────┘    └──────┘ 
1790  quotient.induction_on s $ λ l, by simp [powerset_len_coe]; exact
id   └───────────────────┘                 └──────────────┘
src  └───────────────────┘             └────┘└──────────────┘  └─────
typ  └───────────────────┘           └────┘└──────────────┘  └─────
doc                                    └────┘                  └─────
txt                                    └────┘                  └─────
par                                    └────┘                  └─────
pid                                                               
st                                    └───────────────────────────────
1791    subperm_of_sublist (map_sublist_map _ (sublists_len_sublist_sublists' _ _))
id     └────────────────┘  └─────────────┘    └────────────────────────────┘
src  ─┘└────────────────┘ └─────────────┘└─┘ └────────────────────────────┘└──────
typ  ─┘└────────────────┘ └─────────────┘└─┘ └────────────────────────────┘└──────
doc  ─┘                                  └─┘                               └──────
txt  ─┘                                  └─┘                               └──────
par  ─┘                                  └─┘                               └──────
pid  ─┘                                  └─┘                               └────┘
st   ──────────────────────────────────────────────────────────────────────────────
1792  
src  
typ  
doc  
txt  
par  
pid  
st   
1793  theorem powerset_len_mono (n : ℕ) {s t : multiset α} (h : s ≤ t) :
id                                           └──────┘          
src                                          └──────┘           
typ                                          └──────┘          
doc                                           └──────┘
1794    powerset_len n s ≤ powerset_len n t :=
id     └──────────┘    └──────────┘  
src    └──────────┘      └──────────┘
typ    └──────────┘    └──────────┘  
1795  le_induction_on h $ λ l₁ l₂ h, by simp [powerset_len_coe]; exact
id   └─────────────┘      └┘ └┘            └──────────────┘
src  └─────────────┘                   └────┘└──────────────┘  └─────
typ  └─────────────┘      └┘ └┘      └────┘└──────────────┘  └─────
doc                                    └────┘                  └─────
txt                                    └────┘                  └─────
par                                    └────┘                  └─────
pid                                                               
st                                    └───────────────────────────────
1796    subperm_of_sublist (map_sublist_map _ (sublists_len_sublist_of_sublist _ h))
id     └────────────────┘  └─────────────┘    └─────────────────────────────┘   
src  ─┘└────────────────┘ └─────────────┘└─┘ └─────────────────────────────┘└─┘ └──
typ  ─┘└────────────────┘ └─────────────┘└─┘ └─────────────────────────────┘└─┘└──
doc  ─┘                                  └─┘                                └─┘ └──
txt  ─┘                                  └─┘                                └─┘ └──
par  ─┘                                  └─┘                                └─┘ └──
pid  ─┘                                  └─┘                                └─┘ └┘
st   ───────────────────────────────────────────────────────────────────────────────
1797  
src  
typ  
doc  
txt  
par  
pid  
st   
1798  /- countp -/
src  ─────────────
typ  ─────────────
doc  ─────────────
txt  ─────────────
par  ─────────────
pid  ─────────────
st   ─────────────
1799  
src  
typ  
doc  
txt  
par  
pid  
st   
1800  /-- `countp p s` counts the number of elements of `s` (with multiplicity) that
1801    satisfy `p`. -/
1802  def countp (p : α → Prop) [decidable_pred p] (s : multiset α) : ℕ :=
id                             └────────────┘        └──────┘     
src                             └────────────┘         └──────┘      
typ                            └────────────┘        └──────┘     
doc                                                    └──────┘
1803  quot.lift_on s (countp p) (λ l₁ l₂, perm_countp p)
id   └──────────┘   └────┘      └┘ └┘  └─────────┘ 
src  └──────────┘    └────┘              └─────────┘
typ  └──────────┘   └────┘      └┘ └┘  └─────────┘ 
doc                  └────┘
1804  
1805  @[simp] theorem coe_countp (l : list α) : countp p l = l.countp p := rfl
id                                   └──┘     └────┘    └─────┘     └─┘
src                                  └──┘      └────┘       └─────┘      └─┘
typ                                  └──┘     └────┘    └─────┘     └─┘
doc    └──┘                                    └────┘        └─────┘
1806  
1807  @[simp] theorem countp_zero (p : α → Prop) [decidable_pred p] : countp p 0 = 0 := rfl
id                                              └────────────┘     └────┘          └─┘
src                                              └────────────┘      └────┘           └─┘
typ                                             └────────────┘     └────┘          └─┘
doc    └──┘                                                          └────┘
1808  
1809  @[simp] theorem countp_cons_of_pos {a : α} (s) : p a → countp p (a::s) = countp p s + 1 :=
id                                                       └────┘   └┘   └────┘   
src                                                         └────┘     └┘    └────┘     
typ                                                      └────┘   └┘   └────┘   
doc    └──┘                                                 └────┘     └┘     └────┘
1810  quot.induction_on s countp_cons_of_pos
id   └───────────────┘  └────────────────┘
src  └───────────────┘   └────────────────┘
typ  └───────────────┘  └────────────────┘
1811  
1812  @[simp] theorem countp_cons_of_neg {a : α} (s) : ¬ p a → countp p (a::s) = countp p s :=
id                                                        └────┘   └┘   └────┘  
src                                                          └────┘     └┘    └────┘
typ                                                       └────┘   └┘   └────┘  
doc    └──┘                                                   └────┘     └┘     └────┘
1813  quot.induction_on s countp_cons_of_neg
id   └───────────────┘  └────────────────┘
src  └───────────────┘   └────────────────┘
typ  └───────────────┘  └────────────────┘
1814  
1815  theorem countp_eq_card_filter (s) : countp p s = card (filter p s) :=
id                                       └────┘    └──┘  └────┘  
src                                      └────┘      └──┘  └────┘
typ                                      └────┘    └──┘  └────┘  
doc                                      └────┘       └──┘  └────┘
1816  quot.induction_on s $ λ l, countp_eq_length_filter _
id   └───────────────┘        └─────────────────────┘
src  └───────────────┘          └─────────────────────┘
typ  └───────────────┘        └─────────────────────┘
1817  
1818  @[simp] theorem countp_add (s t) : countp p (s + t) = countp p s + countp p t :=
id                                      └────┘        └────┘    └────┘  
src                                     └────┘           └────┘      └────┘
typ                                     └────┘        └────┘    └────┘  
doc    └──┘                             └────┘             └────┘       └────┘
1819  by simp [countp_eq_card_filter]
id            └───────────────────┘
src     └────┘└───────────────────┘└─
typ     └────┘└───────────────────┘└─
doc     └────┘                     └─
txt     └────┘                     └─
par     └────┘                     └─
pid                              
st     └─────────────────────────────
1820  
src  
typ  
doc  
txt  
par  
pid  
st   
1821  instance countp.is_add_monoid_hom : is_add_monoid_hom (countp p : multiset α → ℕ) :=
id                                       └───────────────┘  └────┘    └──────┘    
src                                      └───────────────┘  └────┘     └──────┘     
typ                                      └───────────────┘  └────┘    └──────┘    
doc                                      └───────────────┘  └────┘     └──────┘
1822  { map_add := countp_add, map_zero := countp_zero _ }
id                └────────┘              └─────────┘
src               └────────┘              └─────────┘
typ               └────────┘              └─────────┘
1823  
1824  theorem countp_pos {s} : 0 < countp p s ↔ ∃ a ∈ s, p a :=
id                               └────┘          
src                              └────┘            
typ                              └────┘          
doc                               └────┘
1825  by simp [countp_eq_card_filter, card_pos_iff_exists_mem]
id            └───────────────────┘  └─────────────────────┘
src     └────┘└───────────────────┘└┘└─────────────────────┘└─
typ     └────┘└───────────────────┘└┘└─────────────────────┘└─
doc     └────┘                     └┘                       └─
txt     └────┘                     └┘                       └─
par     └────┘                     └┘                       └─
pid                              └┘                       
st     └──────────────────────────────────────────────────────
1826  
src  
typ  
doc  
txt  
par  
pid  
st   
1827  @[simp] theorem countp_sub [decidable_eq α] {s t : multiset α} (h : t ≤ s) :
id                               └──────────┘          └──────┘          
src                              └──────────┘           └──────┘           
typ                              └──────────┘          └──────┘          
doc    └──┘                                             └──────┘
1828    countp p (s - t) = countp p s - countp p t :=
id     └────┘        └────┘    └────┘  
src    └────┘           └────┘      └────┘
typ    └────┘        └────┘    └────┘  
doc    └────┘             └────┘       └────┘
1829  by simp [countp_eq_card_filter, h, filter_le_filter]
id            └───────────────────┘    └──────────────┘
src     └────┘└───────────────────┘└┘ └┘└──────────────┘└─
typ     └────┘└───────────────────┘└┘└┘└──────────────┘└─
doc     └────┘                     └┘ └┘                └─
txt     └────┘                     └┘ └┘                └─
par     └────┘                     └┘ └┘                └─
pid                              └┘ └┘                
st     └──────────────────────────────────────────────────
1830  
src  
typ  
doc  
txt  
par  
pid  
st   
1831  theorem countp_pos_of_mem {s a} (h : a ∈ s) (pa : p a) : 0 < countp p s :=
id                                                          └────┘  
src                                                             └────┘
typ                                                         └────┘  
doc                                                               └────┘
1832  countp_pos.2 ⟨_, h, pa⟩
id   └────────┘        └┘
src  └────────┘
typ  └────────┘        └┘
1833  
1834  theorem countp_le_of_le {s t} (h : s ≤ t) : countp p s ≤ countp p t :=
id                                            └────┘    └────┘  
src                                             └────┘      └────┘
typ                                           └────┘    └────┘  
doc                                              └────┘       └────┘
1835  by simpa [countp_eq_card_filter] using card_le_of_le (filter_le_filter h)
id             └───────────────────┘        └───────────┘  └──────────────┘ 
src     └─────┘└───────────────────┘└──────┘└───────────┘ └──────────────┘ └─
typ     └─────┘└───────────────────┘└──────┘└───────────┘ └──────────────┘└─
doc     └─────┘                     └──────┘                               └─
txt     └─────┘                     └──────┘                               └─
par     └─────┘                     └──────┘                               └─
pid                               └────┘                               
st     └───────────────────────────────────────────────────────────────────────
1836  
src  
typ  
doc  
txt  
par  
pid  
st   
1837  @[simp] theorem countp_filter {q} [decidable_pred q] (s : multiset α) :
id                                      └────────────┘        └──────┘ 
src                                     └────────────┘         └──────┘
typ                                     └────────────┘        └──────┘ 
doc    └──┘                                                    └──────┘
1838    countp p (filter q s) = countp (λ a, p a ∧ q a) s :=
id     └────┘   └────┘     └────┘            
src    └────┘    └────┘       └────┘           
typ    └────┘   └────┘     └────┘            
doc    └────┘    └────┘        └────┘
1839  by simp [countp_eq_card_filter]
id            └───────────────────┘
src     └────┘└───────────────────┘└─
typ     └────┘└───────────────────┘└─
doc     └────┘                     └─
txt     └────┘                     └─
par     └────┘                     └─
pid                              
st     └─────────────────────────────
1840  
src  
typ  
doc  
txt  
par  
pid  
st   
1841  end
1842  
1843  /- count -/
1844  
1845  section
1846  variable [decidable_eq α]
id             └──────────┘
src            └──────────┘
typ            └──────────┘
1847  
1848  /-- `count a s` is the multiplicity of `a` in `s`. -/
1849  def count (a : α) : multiset α → ℕ := countp (eq a)
id                      └──────┘        └────┘  └┘ 
src                      └──────┘         └────┘  └┘
typ                     └──────┘        └────┘  └┘ 
doc                      └──────┘          └────┘
1850  
1851  @[simp] theorem coe_count (a : α) (l : list α) : count a (↑l) = l.count a := coe_countp _
id                                         └──┘     └───┘      └────┘     └────────┘
src                                         └──┘      └───┘         └────┘      └────────┘
typ                                        └──┘     └───┘      └────┘     └────────┘
doc    └──┘                                           └───┘           └────┘
1852  
1853  @[simp] theorem count_zero (a : α) : count a 0 = 0 := rfl
id                                       └───┘          └─┘
src                                       └───┘           └─┘
typ                                      └───┘          └─┘
doc    └──┘                               └───┘
1854  
1855  @[simp] theorem count_cons_self (a : α) (s : multiset α) : count a (a::s) = succ (count a s) :=
id                                               └──────┘     └───┘   └┘   └──┘  └───┘  
src                                               └──────┘      └───┘     └┘    └──┘  └───┘
typ                                              └──────┘     └───┘   └┘   └──┘  └───┘  
doc    └──┘                                       └──────┘      └───┘     └┘           └───┘
1856  countp_cons_of_pos _ rfl
id   └────────────────┘   └─┘
src  └────────────────┘   └─┘
typ  └────────────────┘   └─┘
1857  
1858  @[simp] theorem count_cons_of_ne {a b : α} (h : a ≠ b) (s : multiset α) : count a (b::s) = count a s :=
id                                                           └──────┘     └───┘   └┘   └───┘  
src                                                             └──────┘      └───┘     └┘    └───┘
typ                                                          └──────┘     └───┘   └┘   └───┘  
doc    └──┘                                                      └──────┘      └───┘     └┘     └───┘
1859  countp_cons_of_neg _ h
id   └────────────────┘   
src  └────────────────┘
typ  └────────────────┘   
1860  
1861  theorem count_le_of_le (a : α) {s t} : s ≤ t → count a s ≤ count a t :=
id                                              └───┘    └───┘  
src                                                └───┘      └───┘
typ                                             └───┘    └───┘  
doc                                                 └───┘       └───┘
1862  countp_le_of_le
id   └─────────────┘
src  └─────────────┘
typ  └─────────────┘
1863  
1864  theorem count_le_count_cons (a b : α) (s : multiset α) : count a s ≤ count a (b :: s) :=
id                                             └──────┘     └───┘    └───┘    └┘ 
src                                             └──────┘      └───┘      └───┘      └┘
typ                                            └──────┘     └───┘    └───┘    └┘ 
doc                                             └──────┘      └───┘       └───┘      └┘
1865  count_le_of_le _ (le_cons_self _ _)
id   └────────────┘    └──────────┘
src  └────────────┘    └──────────┘
typ  └────────────┘    └──────────┘
1866  
1867  theorem count_singleton (a : α) : count a (a::0) = 1 :=
id                                    └───┘   └┘   
src                                    └───┘     └┘   
typ                                   └───┘   └┘   
doc                                    └───┘     └┘
1868  by simp
src     └────
typ     └────
doc     └────
txt     └────
par     └────
pid         
st     └─────
1869  
src  
typ  
doc  
txt  
par  
pid  
st   
1870  @[simp] theorem count_add (a : α) : ∀ s t, count a (s + t) = count a s + count a t :=
id                                           └───┘        └───┘    └───┘  
src                                             └───┘           └───┘      └───┘
typ                                          └───┘        └───┘    └───┘  
doc    └──┘                                     └───┘             └───┘       └───┘
1871  countp_add
id   └────────┘
src  └────────┘
typ  └────────┘
1872  
1873  instance count.is_add_monoid_hom (a : α) : is_add_monoid_hom (count a : multiset α → ℕ) :=
id                                             └───────────────┘  └───┘    └──────┘    
src                                             └───────────────┘  └───┘     └──────┘     
typ                                            └───────────────┘  └───┘    └──────┘    
doc                                             └───────────────┘  └───┘     └──────┘
1874  countp.is_add_monoid_hom
id   └──────────────────────┘
src  └──────────────────────┘
typ  └──────────────────────┘
1875  
1876  @[simp] theorem count_smul (a : α) (n s) : count a (n • s) = n * count a s :=
id                                             └───┘          └───┘  
src                                             └───┘              └───┘
typ                                            └───┘          └───┘  
doc    └──┘                                     └───┘                 └───┘
1877  by induction n; simp [*, succ_smul', succ_mul]
id                           └────────┘  └──────┘
src     └────────┘   └───────┘└────────┘└┘└──────┘└─
typ     └────────┘  └───────┘└────────┘└┘└──────┘└─
doc     └────────┘   └───────┘          └┘        └─
txt     └────────┘   └───────┘          └┘        └─
par     └────────┘   └───────┘          └┘        └─
pid                     └──┘          └┘        
st     └────────────────────────────────────────────
1878  
src  
typ  
doc  
txt  
par  
pid  
st   
1879  theorem count_pos {a : α} {s : multiset α} : 0 < count a s ↔ a ∈ s :=
id                                 └──────┘        └───┘      
src                                 └──────┘         └───┘        
typ                                └──────┘        └───┘      
doc                                 └──────┘          └───┘
1880  by simp [count, countp_pos]
id            └───┘  └────────┘
src     └────┘└───┘└┘└────────┘└─
typ     └────┘└───┘└┘└────────┘└─
doc     └────┘└───┘└┘          └─
txt     └────┘     └┘          └─
par     └────┘     └┘          └─
pid              └┘          
st     └─────────────────────────
1881  
src  
typ  
doc  
txt  
par  
pid  
st   
1882  @[simp] theorem count_eq_zero_of_not_mem {a : α} {s : multiset α} (h : a ∉ s) : count a s = 0 :=
id                                                        └──────┘              └───┘   
src                                                        └──────┘                 └───┘     
typ                                                       └──────┘              └───┘   
doc    └──┘                                                └──────┘                  └───┘
1883  by_contradiction $ λ h', h $ count_pos.1 (nat.pos_of_ne_zero h')
id   └──────────────┘     └┘     └───────┘   └────────────────┘ └┘
src  └──────────────┘             └───────┘   └────────────────┘
typ  └──────────────┘     └┘     └───────┘   └────────────────┘ └┘
1884  
1885  theorem count_eq_zero {a : α} {s : multiset α} : count a s = 0 ↔ a ∉ s :=
id                                     └──────┘     └───┘         
src                                     └──────┘      └───┘           
typ                                    └──────┘     └───┘         
doc                                     └──────┘      └───┘
1886  iff_not_comm.1 $ count_pos.symm.trans pos_iff_ne_zero
id   └──────────┘    └───────┘└───┘└────┘ └─────────────┘
src  └──────────┘    └───────┘└───┘└────┘ └─────────────┘
typ  └──────────┘    └───────┘└───┘└────┘ └─────────────┘
1887  
1888  @[simp] theorem count_repeat (a : α) (n : ℕ) : count a (repeat a n) = n :=
id                                                └───┘   └────┘     
src                                                └───┘    └────┘      
typ                                               └───┘   └────┘     
doc    └──┘                                         └───┘    └────┘
1889  by simp [repeat]
id            └────┘
src     └────┘└────┘└─
typ     └────┘└────┘└─
doc     └────┘└────┘└─
txt     └────┘      └─
par     └────┘      └─
pid               
st     └──────────────
1890  
src  
typ  
doc  
txt  
par  
pid  
st   
1891  @[simp] theorem count_erase_self (a : α) (s : multiset α) : count a (erase s a) = pred (count a s) :=
id                                                └──────┘     └───┘   └───┘     └──┘  └───┘  
src                                                └──────┘      └───┘    └───┘       └──┘  └───┘
typ                                               └──────┘     └───┘   └───┘     └──┘  └───┘  
doc    └──┘                                        └──────┘      └───┘    └───┘              └───┘
1892  begin
st   └─────
1893    by_cases a ∈ s,
id                
src    └───────┘ 
typ    └───────┘
doc    └───────┘  
txt    └───────┘  
par    └───────┘  
pid              
st   ───────────────┘└─
1894    { rw [(by rw cons_erase h : count a s = count a (a::erase s a)),
id                  └────────┘               └───┘     └┘└───┘  
src      └──┘   └──┘└────────┘ └─┘       └───┘   └┘└───┘  └───
typ      └──┘   └──┘└────────┘└─┘       └───┘   └┘└───┘└───
doc      └──┘   └──┘           └─┘        └───┘   └┘└───┘  └───
txt      └──┘   └──┘           └─┘                         └───
par      └──┘   └──┘           └─┘                         └───
pid        └┘   └──┘           └─┘                         └───
st   ───┘└─────┘└───────────────┘└───────────────────────────────────┘└─
1895          count_cons_self]; refl },
id           └─────────────┘
src  ───────┘└─────────────┘  └───┘
typ  ───────┘└─────────────┘  └───┘
doc  ───────┘                 └───┘
txt  ───────┘                 └───┘
par  ───────┘                 └───┘
pid  ───────┘                     
st   ──────────────────────┘└─────┘└┘
1896    { rw [erase_of_not_mem h, count_eq_zero.2 h]; refl }
id           └──────────────┘   └───────────┘   
src      └──┘└──────────────┘ └┘└───────────┘└─┘   └───┘
typ      └──┘└──────────────┘└┘└───────────┘└─┘  └───┘
doc      └──┘                 └┘             └─┘   └───┘
txt      └──┘                 └┘             └─┘   └───┘
par      └──┘                 └┘             └─┘   └───┘
pid        └┘                 └┘             └─┘       
st   ─────────────────────────┘└─────────────────┘└─────┘└─
1897  end
st   ──┘
1898  
1899  @[simp] theorem count_erase_of_ne {a b : α} (ab : a ≠ b) (s : multiset α) : count a (erase s b) = count a s :=
id                                                             └──────┘     └───┘   └───┘     └───┘  
src                                                               └──────┘      └───┘    └───┘       └───┘
typ                                                            └──────┘     └───┘   └───┘     └───┘  
doc    └──┘                                                        └──────┘      └───┘    └───┘        └───┘
1900  begin
st   └─────
1901    by_cases b ∈ s,
id                
src    └───────┘ 
typ    └───────┘
doc    └───────┘  
txt    └───────┘  
par    └───────┘  
pid              
st   ───────────────┘└─
1902    { rw [← count_cons_of_ne ab, cons_erase h] },
id             └──────────────┘ └┘  └────────┘ 
src      └────┘└──────────────┘  └┘└────────┘ └┘
typ      └────┘└──────────────┘└┘└┘└────────┘└┘
doc      └────┘                  └┘           └┘
txt      └────┘                  └┘           └┘
par      └────┘                  └┘           └┘
pid        └──┘                  └┘           
st   ───┘└───────────────────────┘└────────────┘└┘
1903    { rw [erase_of_not_mem h] }
id           └──────────────┘ 
src      └──┘└──────────────┘ └┘
typ      └──┘└──────────────┘└┘
doc      └──┘                 └┘
txt      └──┘                 └┘
par      └──┘                 └┘
pid        └┘                 
st   ─────────────────────────┘└─
1904  end
st   ──┘
1905  
1906  @[simp] theorem count_sub (a : α) (s t : multiset α) : count a (s - t) = count a s - count a t :=
id                                           └──────┘     └───┘        └───┘    └───┘  
src                                           └──────┘      └───┘           └───┘      └───┘
typ                                          └──────┘     └───┘        └───┘    └───┘  
doc    └──┘                                   └──────┘      └───┘             └───┘       └───┘
1907  begin
st   └─────
1908    revert s, refine multiset.induction_on t (by simp) (λ b t IH s, _),
id                      └───────────────────┘ 
src    └──────┘  └─────┘└───────────────────┘    └──┘└┘  └───────────┘
typ    └──────┘  └─────┘└───────────────────┘   └──┘└┘  └───────────┘
doc    └──────┘  └─────┘                         └──┘└┘  └───────────┘
txt    └──────┘  └─────┘                         └──┘└┘  └───────────┘
par    └──────┘  └─────┘                         └──┘└┘  └───────────┘
pid          └┘                                 └─────┘  └───────────┘
st   ─────────┘└──────────────────────────────────┘└───┘└───────────────┘└─
1909    rw [sub_cons, IH],
id         └──────┘  └┘
src    └──┘└──────┘└┘  
typ    └──┘└──────┘└┘└┘
doc    └──┘        └┘  
txt    └──┘        └┘  
par    └──┘        └┘  
pid      └┘        └┘  
st   ─────────────┘└──┘└──
1910    by_cases ab : a = b,
id                     
src    └───────┘  └─┘ 
typ    └───────┘  └─┘
doc    └───────┘  └─┘  
txt    └───────┘  └─┘  
par    └───────┘  └─┘  
pid              └─┘  
st   ────────────────────┘└─
1911    { subst b, rw [count_erase_self, count_cons_self, sub_succ, pred_sub] },
id                   └──────────────┘  └─────────────┘  └──────┘  └──────┘
src      └────┘   └──┘└──────────────┘└┘└─────────────┘└┘└──────┘└┘└──────┘└┘
typ      └────┘  └──┘└──────────────┘└┘└─────────────┘└┘└──────┘└┘└──────┘└┘
doc      └────┘   └──┘                └┘               └┘        └┘        └┘
txt      └────┘   └──┘                └┘               └┘        └┘        └┘
par      └────┘   └──┘                └┘               └┘        └┘        └┘
pid                └┘                └┘               └┘        └┘        
st   ───┘└─────┘└────────────────────┘└───────────────┘└────────┘└────────┘└┘
1912    { rw [count_erase_of_ne ab, count_cons_of_ne ab] }
id           └───────────────┘ └┘  └──────────────┘ └┘
src      └──┘└───────────────┘  └┘└──────────────┘  └┘
typ      └──┘└───────────────┘└┘└┘└──────────────┘└┘└┘
doc      └──┘                   └┘                  └┘
txt      └──┘                   └┘                  └┘
par      └──┘                   └┘                  └┘
pid        └┘                   └┘                  
st   ───────────────────────────┘└───────────────────┘└─
1913  end
st   ──┘
1914  
1915  @[simp] theorem count_union (a : α) (s t : multiset α) : count a (s ∪ t) = max (count a s) (count a t) :=
id                                             └──────┘     └───┘        └─┘  └───┘     └───┘  
src                                             └──────┘      └───┘           └─┘  └───┘       └───┘
typ                                            └──────┘     └───┘        └─┘  └───┘     └───┘  
doc    └──┘                                     └──────┘      └───┘                  └───┘       └───┘
1916  by simp [(∪), union, sub_add_eq_max, -add_comm]
id                 └───┘  └────────────┘
src     └────┘ └──┘└───┘└┘└────────────┘└────────────
typ     └────┘ └──┘└───┘└┘└────────────┘└────────────
doc     └────┘ └──┘└───┘└┘              └────────────
txt     └────┘ └──┘     └┘              └────────────
par     └────┘ └──┘     └┘              └────────────
pid          └──┘     └┘              └──────────┘
st     └─────────────────────────────────────────────
1917  
src  
typ  
doc  
txt  
par  
pid  
st   
1918  @[simp] theorem count_inter (a : α) (s t : multiset α) : count a (s ∩ t) = min (count a s) (count a t) :=
id                                             └──────┘     └───┘        └─┘  └───┘     └───┘  
src                                             └──────┘      └───┘           └─┘  └───┘       └───┘
typ                                            └──────┘     └───┘        └─┘  └───┘     └───┘  
doc    └──┘                                     └──────┘      └───┘                  └───┘       └───┘
1919  begin
st   └─────
1920    apply @nat.add_left_cancel (count a (s - t)),
id            └─────────────────┘  └───┘     
src    └────┘ └─────────────────┘ └───┘    └┘
typ    └────┘ └─────────────────┘ └───┘ └┘
doc    └────┘                     └───┘     └┘
txt    └────┘                               └┘
par    └────┘                               └┘
pid                                        └┘
st   ─────────────────────────────────────────────┘└─
1921    rw [← count_add, sub_add_inter, count_sub, sub_add_min],
id           └───────┘  └───────────┘  └───────┘  └─────────┘
src    └────┘└───────┘└┘└───────────┘└┘└───────┘└┘└─────────┘
typ    └────┘└───────┘└┘└───────────┘└┘└───────┘└┘└─────────┘
doc    └────┘         └┘             └┘         └┘           
txt    └────┘         └┘             └┘         └┘           
par    └────┘         └┘             └┘         └┘           
pid      └──┘         └┘             └┘         └┘           
st   ────────────────┘└─────────────┘└─────────┘└───────────┘└──
1922  end
st   ──┘
1923  
1924  lemma count_bind {m : multiset β} {f : β → multiset α} {a : α} :
id                         └──────┘           └──────┘        
src                        └──────┘             └──────┘
typ                        └──────┘           └──────┘        
doc                        └──────┘             └──────┘
1925    count a (bind m f) = sum (m.map $ λb, count a $ f b) :=
id     └───┘   └──┘     └─┘  └──┘      └───┘     
src    └───┘    └──┘       └─┘   └──┘       └───┘
typ    └───┘   └──┘     └─┘  └──┘      └───┘     
doc    └───┘    └──┘              └──┘       └───┘
1926  multiset.induction_on m (by simp) (by simp)
id   └───────────────────┘ 
src  └───────────────────┘       └──┘      └──┘
typ  └───────────────────┘      └──┘      └──┘
doc                              └──┘      └──┘
txt                              └──┘      └──┘
par                              └──┘      └──┘
st                              └───┘     └───┘
1927  
1928  theorem le_count_iff_repeat_le {a : α} {s : multiset α} {n : ℕ} : n ≤ count a s ↔ repeat a n ≤ s :=
id                                              └──────┘              └───┘    └────┘    
src                                              └──────┘                └───┘      └────┘     
typ                                             └──────┘              └───┘    └────┘    
doc                                              └──────┘                  └───┘       └────┘
1929  quot.induction_on s $ λ l, le_count_iff_repeat_sublist.trans repeat_le_coe.symm
id   └───────────────┘        └─────────────────────────┘└────┘ └───────────┘└───┘
src  └───────────────┘          └─────────────────────────┘└────┘ └───────────┘└───┘
typ  └───────────────┘        └─────────────────────────┘└────┘ └───────────┘└───┘
1930  
1931  @[simp] theorem count_filter {p} [decidable_pred p]
id                                     └────────────┘ 
src                                    └────────────┘
typ                                    └────────────┘ 
doc    └──┘
1932    {a} {s : multiset α} (h : p a) : count a (filter p s) = count a s :=
id              └──────┘             └───┘   └────┘     └───┘  
src             └──────┘                └───┘    └────┘       └───┘
typ             └──────┘             └───┘   └────┘     └───┘  
doc             └──────┘                └───┘    └────┘        └───┘
1933  quot.induction_on s $ λ l, count_filter h
id   └───────────────┘        └──────────┘ 
src  └───────────────┘          └──────────┘
typ  └───────────────┘        └──────────┘ 
1934  
1935  theorem ext {s t : multiset α} : s = t ↔ ∀ a, count a s = count a t :=
id                      └──────┘             └───┘    └───┘  
src                     └──────┘                 └───┘      └───┘
typ                     └──────┘             └───┘    └───┘  
doc                     └──────┘                   └───┘       └───┘
1936  quotient.induction_on₂ s t $ λ l₁ l₂, quotient.eq.trans perm_iff_count
id   └────────────────────┘       └┘ └┘  └─────────┘└────┘ └────────────┘
src  └────────────────────┘                └─────────┘└────┘ └────────────┘
typ  └────────────────────┘       └┘ └┘  └─────────┘└────┘ └────────────┘
1937  
1938  @[ext]
doc    └─┘
1939  theorem ext' {s t : multiset α} : (∀ a, count a s = count a t) → s = t :=
id                       └──────┘          └───┘    └───┘        
src                      └──────┘            └───┘      └───┘          
typ                      └──────┘          └───┘    └───┘        
doc                      └──────┘            └───┘       └───┘
1940  ext.2
id   └─┘
src  └─┘
typ  └─┘
1941  
1942  @[simp] theorem coe_inter (s t : list α) : (s ∩ t : multiset α) = (s.bag_inter t : list α) :=
id                                    └──┘           └──────┘     └────────┘    └──┘ 
src                                   └──┘              └──────┘       └────────┘     └──┘
typ                                   └──┘           └──────┘     └────────┘    └──┘ 
doc    └──┘                                              └──────┘
1943  by ext; simp
src     └─┘  └────
typ     └─┘  └────
doc     └─┘  └────
txt     └─┘  └────
par     └─┘  └────
pid              
st     └──────────
1944  
src  
typ  
doc  
txt  
par  
pid  
st   
1945  theorem le_iff_count {s t : multiset α} : s ≤ t ↔ ∀ a, count a s ≤ count a t :=
id                               └──────┘             └───┘    └───┘  
src                              └──────┘                 └───┘      └───┘
typ                              └──────┘             └───┘    └───┘  
doc                              └──────┘                   └───┘       └───┘
1946  ⟨λ h a, count_le_of_le a h, λ al,
id         └────────────┘      └┘
src          └────────────┘
typ        └────────────┘      └┘
1947   by rw ← (ext.2 (λ a, by simp [max_eq_right (al a)]) : s ∪ t = t);
id             └─┘                  └──────────┘  └┘            
src      └───┘ └─┘└─┘  └──┘  └────┘└──────────┘    └┘└──┘   
typ      └───┘ └─┘└─┘  └──┘  └────┘└──────────┘ └┘└┘└──┘ 
doc      └───┘    └─┘  └──┘  └────┘                └┘└──┘     
txt      └───┘    └─┘  └──┘  └────┘                └┘└──┘     
par      └───┘    └─┘  └──┘  └────┘                └┘└──┘     
pid        └─┘    └─┘  └──┘  └─────┘                └────┘     
st      └───────────────────┘└─────────────────────────┘└───────────────
1948      apply le_union_left⟩
id             └───────────┘
src      └────┘└───────────┘
typ      └────┘└───────────┘
doc      └────┘
txt      └────┘
par      └────┘
pid           
st   ──────────────────────┘
1949  
1950  instance : distrib_lattice (multiset α) :=
id              └─────────────┘  └──────┘ 
src             └─────────────┘  └──────┘
typ             └─────────────┘  └──────┘ 
doc             └─────────────┘  └──────┘
1951  { le_sup_inf := λ s t u, le_of_eq $ eq.symm $
id                         └──────┘   └─────┘
src                           └──────┘   └─────┘
typ                        └──────┘   └─────┘
1952      ext.2 $ λ a, by simp only [max_min_distrib_left,
id       └─┘                      └──────────────────┘
src      └─┘            └─────────┘└──────────────────┘└─
typ      └─┘           └─────────┘└──────────────────┘└─
doc                      └─────────┘                    └─
txt                      └─────────┘                    └─
par                      └─────────┘                    └─
pid                          └──┘└┘                    └─
st                      └─────────────────────────────────
1953        multiset.count_inter, multiset.sup_eq_union, multiset.count_union, multiset.inf_eq_inter],
id         └──────────────────┘  └───────────────────┘  └──────────────────┘  └───────────────────┘
src  ─────┘└──────────────────┘└┘└───────────────────┘└┘└──────────────────┘└┘└───────────────────┘
typ  ─────┘└──────────────────┘└┘└───────────────────┘└┘└──────────────────┘└┘└───────────────────┘
doc  ─────┘                    └┘                     └┘                    └┘                     
txt  ─────┘                    └┘                     └┘                    └┘                     
par  ─────┘                    └┘                     └┘                    └┘                     
pid  ─────┘                    └┘                     └┘                    └┘                     
st   ──────────────────────────────────────────────────────────────────────────────────────────────┘
1954    ..multiset.lattice.lattice }
id       └──────────────────────┘
src      └──────────────────────┘
typ      └──────────────────────┘
1955  
1956  instance : semilattice_sup_bot (multiset α) :=
id              └─────────────────┘  └──────┘ 
src             └─────────────────┘  └──────┘
typ             └─────────────────┘  └──────┘ 
doc             └─────────────────┘  └──────┘
1957  { bot := 0,
1958    bot_le := zero_le,
id               └─────┘
src              └─────┘
typ              └─────┘
1959    ..multiset.lattice.lattice }
id       └──────────────────────┘
src      └──────────────────────┘
typ      └──────────────────────┘
1960  
1961  end
1962  
1963  /- relator -/
1964  
1965  section rel
1966  
1967  /-- `rel r s t` -- lift the relation `r` between two elements to a relation between `s` and `t`,
1968  s.t. there is a one-to-one mapping betweem elements in `s` and `t` following `r`. -/
1969  inductive rel (r : α → β → Prop) : multiset α → multiset β → Prop
id                                    └──────┘     └──────┘
src                                     └──────┘     └──────┘
typ                                   └──────┘     └──────┘
doc                                     └──────┘     └──────┘
1970  | zero {} : rel 0 0
1971  | cons {a b as bs} : r a b → rel as bs → rel (a :: as) (b :: bs)
id             └┘ └┘         └─┘ └┘ └┘         └┘ └┘    └┘ └┘
src                                                  └┘        └┘
typ            └┘ └┘         └─┘ └┘ └┘         └┘ └┘    └┘ └┘
doc                                                  └┘        └┘
1972  
1973  run_cmd tactic.mk_iff_of_inductive_prop `multiset.rel `multiset.rel_iff
id           └─────────────────────────────┘              
src          └─────────────────────────────┘              
typ          └─────────────────────────────┘              
doc          └─────────────────────────────┘
1974  
1975  variables {δ : Type*} {r : α → β → Prop} {p : γ → δ → Prop}
1976  
1977  private lemma rel_flip_aux {s t} (h : rel r s t) : rel (flip r) t s :=
id                                         └─┘       └─┘  └──┘    
src                                        └─┘          └─┘  └──┘
typ                                        └─┘       └─┘  └──┘    
doc                                        └─┘          └─┘
1978  rel.rec_on h rel.zero (assume _ _ _ _ h₀ h₁ ih, rel.cons h₀ ih)
id   └────────┘  └──────┘             └┘ └┘ └┘  └──────┘ └┘ └┘
src  └────────┘   └──────┘                           └──────┘
typ  └────────┘  └──────┘             └┘ └┘ └┘  └──────┘ └┘ └┘
1979  
1980  lemma rel_flip {s t} : rel (flip r) s t ↔ rel r t s :=
id                          └─┘  └──┘      └─┘   
src                         └─┘  └──┘         └─┘
typ                         └─┘  └──┘      └─┘   
doc                         └─┘                └─┘
1981  ⟨rel_flip_aux, rel_flip_aux⟩
id    └──────────┘  └──────────┘
src   └──────────┘  └──────────┘
typ   └──────────┘  └──────────┘
1982  
1983  lemma rel_eq_refl {s : multiset α} : rel (=) s s :=
id                          └──────┘     └─┘     
src                         └──────┘      └─┘ 
typ                         └──────┘     └─┘     
doc                         └──────┘      └─┘
1984  multiset.induction_on s rel.zero (assume a s, rel.cons rfl)
id   └───────────────────┘  └──────┘            └──────┘ └─┘
src  └───────────────────┘   └──────┘              └──────┘ └─┘
typ  └───────────────────┘  └──────┘            └──────┘ └─┘
1985  
1986  lemma rel_eq {s t : multiset α} : rel (=) s t ↔ s = t :=
id                       └──────┘     └─┘         
src                      └──────┘      └─┘           
typ                      └──────┘     └─┘         
doc                      └──────┘      └─┘
1987  begin
st   └─────
1988    split,
src    └───┘
typ    └───┘
doc    └───┘
txt    └───┘
par    └───┘
st   ──────┘└─
1989    { assume h, induction h; simp * },
id                           
src      └──────┘  └────────┘   └─────┘
typ      └──────┘  └────────┘  └─────┘
doc      └──────┘  └────────┘   └─────┘
txt      └──────┘  └────────┘   └─────┘
par      └──────┘  └────────┘   └─────┘
pid      └──────┘                  
st   ───┘└──────┘└────────────────────┘└┘
1990    { assume h, subst h, exact rel_eq_refl }
id                               └─────────┘
src      └──────┘  └────┘   └────┘└─────────┘
typ      └──────┘  └────┘  └────┘└─────────┘
doc      └──────┘  └────┘   └────┘           
txt      └──────┘  └────┘   └────┘           
par      └──────┘  └────┘   └────┘           
pid      └──────┘                          
st   ───────────┘└───────┘└──────────────────┘└─
1991  end
st   ──┘
1992  
1993  lemma rel.mono {p : α → β → Prop} {s t} (h : ∀a b, r a b → p a b) (hst : rel r s t) : rel p s t :=
id                                                                  └─┘       └─┘   
src                                                                           └─┘          └─┘
typ                                                                 └─┘       └─┘   
doc                                                                           └─┘          └─┘
1994  begin
st   └─────
1995    induction hst,
id               └─┘
src    └────────┘
typ    └────────┘└─┘
doc    └────────┘
txt    └────────┘
par    └────────┘
pid             
st   ──────────────┘└─
1996    case rel.zero { exact rel.zero },
id                           └──────┘
src    └──────────────┘└────┘└──────┘
typ    └──────────────┘└────┘└──────┘
doc    └──────────────┘└────┘        
txt    └──────────────┘└────┘        
par    └──────────────┘└────┘        
pid        └───────┘└──────┘        └┘
st   ────────────────┘└──────────────┘└┘
1997    case rel.cons : a b s t hab hst ih { exact ih.cons (h a b hab) }
id                                                └─────┘     └─┘
src    └───────────────────────────────────┘└────┘└─────┘       └┘└┘
typ    └───────────────────────────────────┘└────┘└─────┘ └─┘└┘└┘
doc    └───────────────────────────────────┘└────┘              └┘└┘
txt    └───────────────────────────────────┘└────┘              └┘└┘
par    └───────────────────────────────────┘└────┘              └┘└┘
pid        └───────┘└───────────────────┘└───────┘              └─┘
st   ─────────────────────────────────────┘└─────────────────────────┘
1998  end
st   └─┘
1999  
2000  lemma rel.add {s t u v} (hst : rel r s t) (huv : rel r u v) : rel r (s + u) (t + v) :=
id                                  └─┘            └─┘       └─┘          
src                                 └─┘               └─┘          └─┘             
typ                                 └─┘            └─┘       └─┘          
doc                                 └─┘               └─┘          └─┘
2001  begin
st   └─────
2002    induction hst,
id               └─┘
src    └────────┘
typ    └────────┘└─┘
doc    └────────┘
txt    └────────┘
par    └────────┘
pid             
st   ──────────────┘└─
2003    case rel.zero { simpa using huv },
id                                 └─┘
src    └──────────────┘└──────────┘   
typ    └──────────────┘└──────────┘└─┘
doc    └──────────────┘└──────────┘   
txt    └──────────────┘└──────────┘   
par    └──────────────┘└──────────┘   
pid        └───────┘└────────────┘   └┘
st   ────────────────┘└───────────────┘└┘
2004    case rel.cons : a b s t hab hst ih { simpa using ih.cons hab }
id                                                      └─────┘ └─┘
src    └───────────────────────────────────┘└──────────┘└─────┘   └┘
typ    └───────────────────────────────────┘└──────────┘└─────┘└─┘└┘
doc    └───────────────────────────────────┘└──────────┘          └┘
txt    └───────────────────────────────────┘└──────────┘          └┘
par    └───────────────────────────────────┘└──────────┘          └┘
pid        └───────┘└───────────────────┘└─────────────┘          └┘
st   ─────────────────────────────────────┘└───────────────────────┘
2005  end
st   └─┘
2006  
2007  lemma rel_flip_eq  {s t : multiset α} : rel (λa b, b = a) s t ↔ s = t :=
id                             └──────┘     └─┘               
src                            └──────┘      └─┘                     
typ                            └──────┘     └─┘               
doc                            └──────┘      └─┘
2008  show rel (flip (=)) s t ↔ s = t, by rw [rel_flip, rel_eq, eq_comm]
id        └─┘  └──┘                   └──────┘  └────┘  └─────┘
src       └─┘  └──┘                   └──┘└──────┘└┘└────┘└┘└─────┘└─
typ       └─┘  └──┘               └──┘└──────┘└┘└────┘└┘└─────┘└─
doc       └─┘                            └──┘        └┘      └┘       └─
txt                                      └──┘        └┘      └┘       └─
par                                      └──┘        └┘      └┘       └─
pid                                        └┘        └┘      └┘       
st                                      └───────────┘└──────┘└───────┘
2009  
src  
typ  
doc  
txt  
par  
pid  
st   
2010  @[simp] lemma rel_zero_left {b : multiset β} : rel r 0 b ↔ b = 0 :=
id                                    └──────┘     └─┘       
src                                   └──────┘      └─┘          
typ                                   └──────┘     └─┘       
doc    └──┘                           └──────┘      └─┘
2011  by rw [rel_iff]; simp
id          └─────┘
src     └──┘└─────┘  └────
typ     └──┘└─────┘  └────
doc     └──┘         └────
txt     └──┘         └────
par     └──┘         └────
pid       └┘             
st     └──────────┘└──────
2012  
src  
typ  
doc  
txt  
par  
pid  
st   
2013  @[simp] lemma rel_zero_right {a : multiset α} : rel r a 0 ↔ a = 0 :=
id                                     └──────┘     └─┘       
src                                    └──────┘      └─┘          
typ                                    └──────┘     └─┘       
doc    └──┘                            └──────┘      └─┘
2014  by rw [rel_iff]; simp
id          └─────┘
src     └──┘└─────┘  └────
typ     └──┘└─────┘  └────
doc     └──┘         └────
txt     └──┘         └────
par     └──┘         └────
pid       └┘             
st     └──────────┘└──────
2015  
src  
typ  
doc  
txt  
par  
pid  
st   
2016  lemma rel_cons_left {a as bs} :
2017    rel r (a :: as) bs ↔ (∃b bs', r a b ∧ rel r as bs' ∧ bs = b :: bs') :=
id     └─┘    └┘ └┘  └┘    └─┘     └─┘  └┘ └─┘  └┘   └┘ └─┘
src    └─┘      └┘                       └─┘                 └┘
typ    └─┘    └┘ └┘  └┘    └─┘     └─┘  └┘ └─┘  └┘   └┘ └─┘
doc    └─┘      └┘                           └─┘                   └┘
2018  begin
st   └─────
2019    split,
src    └───┘
typ    └───┘
doc    └───┘
txt    └───┘
par    └───┘
st   ──────┘└─
2020    { generalize hm : a :: as = m,
id                        └┘ └┘
src      └──────────────┘ └┘   
typ      └──────────────┘└┘└┘ 
doc      └──────────────┘ └┘   
txt      └──────────────┘      
par      └──────────────┘      
pid                └─┘└┘      
st   ───┘└─────────────────────────┘└─
2021      assume h,
src      └──────┘
typ      └──────┘
doc      └──────┘
txt      └──────┘
par      └──────┘
pid      └──────┘
st   ───────────┘└─
2022      induction h generalizing as,
id                 
src      └────────┘ └──────────────┘
typ      └────────┘└──────────────┘
doc      └────────┘ └──────────────┘
txt      └────────┘ └──────────────┘
par      └────────┘ └──────────────┘
pid                └─────────────┘
st   ──────────────────────────────┘└─
2023      case rel.zero { simp at hm, contradiction },
src      └──────────────┘└────────┘└┘└────────────┘
typ      └──────────────┘└────────┘└┘└────────────┘
doc      └──────────────┘└────────┘└┘└────────────┘
txt      └──────────────┘└────────┘└┘└────────────┘
par      └──────────────┘└────────┘└┘└────────────┘
pid          └───────┘└───────────────────────────┘
st   ──────────────────┘└─────────┘└──────────────┘└┘
2024      case rel.cons : a' b as' bs ha'b h ih {
src      └───────────────────────────────────────
typ      └───────────────────────────────────────
doc      └───────────────────────────────────────
txt      └───────────────────────────────────────
par      └───────────────────────────────────────
pid          └───────┘└──────────────────────┘└──
st   ──────────────────────────────────────────┘
2025        rcases cons_eq_cons.1 hm with ⟨eq₁, eq₂⟩ | ⟨h, cs, eq₁, eq₂⟩,
id                └──────────┘   └┘
src  ─────┘└─────┘└──────────┘└─┘  └──────────────────────────────────┘└─
typ  ─────┘└─────┘└──────────┘└─┘└┘└──────────────────────────────────┘└─
doc  ─────┘└─────┘            └─┘  └──────────────────────────────────┘└─
txt  ─────┘└─────┘            └─┘  └──────────────────────────────────┘└─
par  ─────┘└─────┘            └─┘  └──────────────────────────────────┘└─
pid  ────────────┘            └─┘  └─────────────────────────────────────
st   ─────────────────────────────────────────────────────────────────┘└─
2026        { subst eq₁, subst eq₂, exact ⟨b, bs, ha'b, h, rfl⟩ },
id                 └─┘        └─┘           └┘  └──┘    └─┘
src  ───────┘└────┘   └┘└────┘   └┘└────┘  └┘  └┘    └┘ └┘└─┘└┘└──
typ  ───────┘└────┘└─┘└┘└────┘└─┘└┘└────┘ └┘└┘└┘└──┘└┘└┘└─┘└┘└──
doc  ───────┘└────┘   └┘└────┘   └┘└────┘  └┘  └┘    └┘ └┘   └┘└──
txt  ───────┘└────┘   └┘└────┘   └┘└────┘  └┘  └┘    └┘ └┘   └┘└──
par  ───────┘└────┘   └┘└────┘   └┘└────┘  └┘  └┘    └┘ └┘   └┘└──
pid  ─────────────┘   └──────┘   └──────┘  └┘  └┘    └┘ └┘   └────
st   ──────┘└────────┘└─────────┘└────────────────────────────┘└─
2027        { rcases ih eq₂.symm with ⟨b', bs', h₁, h₂, eq⟩,
id                  └┘ └──────┘
src  ───────┘└─────┘  └──────┘└─────────────────────────┘└─
typ  ───────┘└─────┘└┘└──────┘└─────────────────────────┘└─
doc  ───────┘└─────┘          └─────────────────────────┘└─
txt  ───────┘└─────┘          └─────────────────────────┘└─
par  ───────┘└─────┘          └─────────────────────────┘└─
pid  ──────────────┘          └────────────────────────────
st   ────────────────────────────────────────────────────┘└─
2028          exact ⟨b', b::bs', h₁, eq₁.symm ▸ rel.cons ha'b h₂, eq.symm ▸ cons_swap _ _ _⟩  }
id                  └┘    └─┘  └┘  └──────┘  └──────┘ └──┘ └┘  └─────┘   └───────┘
src  ───────┘└────┘   └┘      └┘  └┘└──────┘└──────┘      └┘└─────┘ └───────┘└───────┘└─
typ  ───────┘└────┘ └┘└┘  └─┘└┘└┘└┘└──────┘└──────┘└──┘└┘└┘└─────┘ └───────┘└───────┘└─
doc  ───────┘└────┘   └┘      └┘  └┘                       └┘                 └───────┘└─
txt  ───────┘└────┘   └┘      └┘  └┘                       └┘                 └───────┘└─
par  ───────┘└────┘   └┘      └┘  └┘                       └┘                 └───────┘└─
pid  ─────────────┘   └┘      └┘  └┘                       └┘                 └──────────
st   ───────────────────────────────────────────────────────────────────────────────────────┘└─
2029      } },
src  ─────┘
typ  ─────┘
doc  ─────┘
txt  ─────┘
par  ─────┘
pid  ────┘
st   ────┘└┘
2030    { exact assume ⟨b, bs', hab, h, eq⟩, eq.symm ▸ rel.cons hab h }
id                             └─┘    └┘     └───┘   └──────┘
src      └────┘      └┘ └┘   └┘   └┘ └┘└┘└─┘  └───┘ └──────┘    
typ      └────┘      └┘ └┘   └┘└─┘└┘└┘└┘└─┘  └───┘ └──────┘    
doc      └────┘      └┘ └┘   └┘   └┘ └┘  └─┘                    
txt      └────┘      └┘ └┘   └┘   └┘ └┘  └─┘                    
par      └────┘      └┘ └┘   └┘   └┘ └┘  └─┘                    
pid                 └┘ └┘   └┘   └┘ └┘  └─┘                    
st   ───────────────────────────────────────────────────────────────┘└─
2031  end
st   ──┘
2032  
2033  lemma rel_cons_right {as b bs} :
2034    rel r as (b :: bs) ↔ (∃a as', r a b ∧ rel r as' bs ∧ as = a :: as') :=
id     └─┘  └┘   └┘ └┘     └─┘     └─┘  └─┘ └┘  └┘   └┘ └─┘
src    └─┘         └┘                    └─┘                 └┘
typ    └─┘  └┘   └┘ └┘     └─┘     └─┘  └─┘ └┘  └┘   └┘ └─┘
doc    └─┘         └┘                        └─┘                   └┘
2035  begin
st   └─────
2036    rw [← rel_flip, rel_cons_left],
id           └──────┘  └───────────┘
src    └────┘└──────┘└┘└───────────┘
typ    └────┘└──────┘└┘└───────────┘
doc    └────┘        └┘             
txt    └────┘        └┘             
par    └────┘        └┘             
pid      └──┘        └┘             
st   ───────────────┘└─────────────┘└──
2037    apply exists_congr, assume a,
id           └──────────┘
src    └────┘└──────────┘  └──────┘
typ    └────┘└──────────┘  └──────┘
doc    └────┘              └──────┘
txt    └────┘              └──────┘
par    └────┘              └──────┘
pid                       └──────┘
st   ───────────────────┘└────────┘└─
2038    apply exists_congr, assume as',
id           └──────────┘
src    └────┘└──────────┘  └────────┘
typ    └────┘└──────────┘  └────────┘
doc    └────┘              └────────┘
txt    └────┘              └────────┘
par    └────┘              └────────┘
pid                       └────────┘
st   ───────────────────┘└──────────┘└─
2039    rw [rel_flip, flip]
id         └──────┘  └──┘
src    └──┘└──────┘└┘└──┘└┘
typ    └──┘└──────┘└┘└──┘└┘
doc    └──┘        └┘    └┘
txt    └──┘        └┘    └┘
par    └──┘        └┘    └┘
pid      └┘        └┘    
st   ─────────────┘└────┘
2040  end
st   └─┘
2041  
2042  lemma rel_add_left {as₀ as₁} :
2043    ∀{bs}, rel r (as₀ + as₁) bs ↔ (∃bs₀ bs₁, rel r as₀ bs₀ ∧ rel r as₁ bs₁ ∧ bs = bs₀ + bs₁) :=
id       └┘   └─┘   └─┘  └─┘  └┘   └─┘ └─┘ └─┘  └─┘ └─┘  └─┘  └─┘ └─┘  └┘  └─┘  └─┘
src           └─┘                           └─┘            └─┘                    
typ      └┘   └─┘   └─┘  └─┘  └┘   └─┘ └─┘ └─┘  └─┘ └─┘  └─┘  └─┘ └─┘  └┘  └─┘  └─┘
doc           └─┘                               └─┘             └─┘
2044  multiset.induction_on as₀ (by simp)
id   └───────────────────┘ └─┘
src  └───────────────────┘         └──┘
typ  └───────────────────┘ └─┘     └──┘
doc                                └──┘
txt                                └──┘
par                                └──┘
st                                └───┘
2045    begin
st     └─────
2046      assume a s ih bs,
src      └──────────────┘
typ      └──────────────┘
doc      └──────────────┘
txt      └──────────────┘
par      └──────────────┘
pid      └──────────────┘
st   ───────────────────┘└─
2047      simp only [ih, cons_add, rel_cons_left],
id                      └──────┘  └───────────┘
src      └─────────┘  └┘└──────┘└┘└───────────┘
typ      └─────────┘└┘└┘└──────┘└┘└───────────┘
doc      └─────────┘  └┘        └┘             
txt      └─────────┘  └┘        └┘             
par      └─────────┘  └┘        └┘             
pid          └──┘└┘  └┘        └┘             
st   ──────────────────────────────────────────┘└─
2048      split,
src      └───┘
typ      └───┘
doc      └───┘
txt      └───┘
par      └───┘
st   ────────┘└─
2049      { assume h,
src        └──────┘
typ        └──────┘
doc        └──────┘
txt        └──────┘
par        └──────┘
pid        └──────┘
st   ─────┘└──────┘└─
2050        rcases h with ⟨b, bs', hab, h, rfl⟩,
id                
src        └─────┘ └─────────────────────────┘
typ        └─────┘└─────────────────────────┘
doc        └─────┘ └─────────────────────────┘
txt        └─────┘ └─────────────────────────┘
par        └─────┘ └─────────────────────────┘
pid               └─────────────────────────┘
st   ────────────────────────────────────────┘└─
2051        rcases h with ⟨bs₀, bs₁, h₀, h₁, rfl⟩,
id                
src        └─────┘ └───────────────────────────┘
typ        └─────┘└───────────────────────────┘
doc        └─────┘ └───────────────────────────┘
txt        └─────┘ └───────────────────────────┘
par        └─────┘ └───────────────────────────┘
pid               └───────────────────────────┘
st   ──────────────────────────────────────────┘└─
2052        exact ⟨b :: bs₀, bs₁, ⟨b, bs₀, hab, h₀, rfl⟩, h₁, by simp⟩ },
id                  └┘      └─┘     └─┘  └─┘  └┘  └─┘   └┘
src        └────┘  └┘   └┘   └┘  └┘   └┘   └┘  └┘└─┘└─┘  └┘  └──┘└┘
typ        └────┘  └┘   └┘└─┘└┘ └┘└─┘└┘└─┘└┘└┘└┘└─┘└─┘└┘└┘  └──┘└┘
doc        └────┘  └┘   └┘   └┘  └┘   └┘   └┘  └┘   └─┘  └┘  └──┘└┘
txt        └────┘       └┘   └┘  └┘   └┘   └┘  └┘   └─┘  └┘  └──┘└┘
par        └────┘       └┘   └┘  └┘   └┘   └┘  └┘   └─┘  └┘  └──┘└┘
pid                    └┘   └┘  └┘   └┘   └┘  └┘   └─┘  └┘  └────┘
st   ─────────────────────────────────────────────────────────┘└───┘└┘└┘
2053      { assume h,
src        └──────┘
typ        └──────┘
doc        └──────┘
txt        └──────┘
par        └──────┘
pid        └──────┘
st   ─────────────┘└─
2054        rcases h with ⟨bs₀, bs₁, h, h₁, rfl⟩,
id                
src        └─────┘ └──────────────────────────┘
typ        └─────┘└──────────────────────────┘
doc        └─────┘ └──────────────────────────┘
txt        └─────┘ └──────────────────────────┘
par        └─────┘ └──────────────────────────┘
pid               └──────────────────────────┘
st   ─────────────────────────────────────────┘└─
2055        rcases h with ⟨b, bs, hab, h₀, rfl⟩,
id                
src        └─────┘ └─────────────────────────┘
typ        └─────┘└─────────────────────────┘
doc        └─────┘ └─────────────────────────┘
txt        └─────┘ └─────────────────────────┘
par        └─────┘ └─────────────────────────┘
pid               └─────────────────────────┘
st   ────────────────────────────────────────┘└─
2056        exact ⟨b, bs + bs₁, hab, ⟨bs, bs₁, h₀, h₁, rfl⟩, by simp⟩ }
id                           └─┘   └┘  └─┘  └┘  └┘  └─┘
src        └────┘  └┘     └┘   └┘   └┘   └┘  └┘  └┘└─┘└─┘  └──┘└┘
typ        └────┘ └┘     └┘└─┘└┘ └┘└┘└─┘└┘└┘└┘└┘└┘└─┘└─┘  └──┘└┘
doc        └────┘  └┘      └┘   └┘   └┘   └┘  └┘  └┘   └─┘  └──┘└┘
txt        └────┘  └┘      └┘   └┘   └┘   └┘  └┘  └┘   └─┘  └──┘└┘
par        └────┘  └┘      └┘   └┘   └┘   └┘  └┘  └┘   └─┘  └──┘└┘
pid               └┘      └┘   └┘   └┘   └┘  └┘  └┘   └─┘  └────┘
st   ────────────────────────────────────────────────────────┘└───┘└┘└─
2057    end
st   ────┘
2058  
2059  lemma rel_add_right {as bs₀ bs₁} :
2060    rel r as (bs₀ + bs₁) ↔ (∃as₀ as₁, rel r as₀ bs₀ ∧ rel r as₁ bs₁ ∧ as = as₀ + as₁) :=
id     └─┘  └┘  └─┘  └─┘    └─┘ └─┘ └─┘  └─┘ └─┘  └─┘  └─┘ └─┘  └┘  └─┘  └─┘
src    └─┘                           └─┘            └─┘                    
typ    └─┘  └┘  └─┘  └─┘    └─┘ └─┘ └─┘  └─┘ └─┘  └─┘  └─┘ └─┘  └┘  └─┘  └─┘
doc    └─┘                               └─┘             └─┘
2061  by rw [← rel_flip, rel_add_left]; simp [rel_flip]
id            └──────┘  └──────────┘         └──────┘
src     └────┘└──────┘└┘└──────────┘  └────┘└──────┘└─
typ     └────┘└──────┘└┘└──────────┘  └────┘└──────┘└─
doc     └────┘        └┘              └────┘        └─
txt     └────┘        └┘              └────┘        └─
par     └────┘        └┘              └────┘        └─
pid       └──┘        └┘                          
st     └─────────────┘└────────────┘└─────────────────
2062  
src  
typ  
doc  
txt  
par  
pid  
st   
2063  lemma rel_map_left {s : multiset γ} {f : γ → α} :
id                           └──────┘           
src                          └──────┘
typ                          └──────┘           
doc                          └──────┘
2064    ∀{t}, rel r (s.map f) t ↔ rel (λa b, r (f a) b) s t :=
id          └─┘   └──┘     └─┘              
src          └─┘     └──┘       └─┘
typ         └─┘   └──┘     └─┘              
doc          └─┘     └──┘        └─┘
2065  multiset.induction_on s (by simp) (by simp [rel_cons_left] {contextual := tt})
id   └───────────────────┘                      └───────────┘                 └┘
src  └───────────────────┘       └──┘      └────┘└───────────┘└┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └────┘└───────────┘└┘ └────────────┘└┘
doc                              └──┘      └────┘             └┘ └────────────┘  
txt                              └──┘      └────┘             └┘ └────────────┘  
par                              └──┘      └────┘             └┘ └────────────┘  
pid                                                          └────────────┘  
st                              └───┘     └──────────────────────────────────────┘
2066  
2067  lemma rel_map_right {s : multiset α} {t : multiset γ} {f : γ → β} :
id                            └──────┘        └──────┘           
src                           └──────┘         └──────┘
typ                           └──────┘        └──────┘           
doc                           └──────┘         └──────┘
2068    rel r s (t.map f) ↔ rel (λa b, r a (f b)) s t :=
id     └─┘    └──┘    └─┘              
src    └─┘       └──┘     └─┘
typ    └─┘    └──┘    └─┘              
doc    └─┘       └──┘      └─┘
2069  by rw [← rel_flip, rel_map_left, ← rel_flip]; refl
id            └──────┘  └──────────┘    └──────┘
src     └────┘└──────┘└┘└──────────┘└──┘└──────┘  └────
typ     └────┘└──────┘└┘└──────────┘└──┘└──────┘  └────
doc     └────┘        └┘            └──┘          └────
txt     └────┘        └┘            └──┘          └────
par     └────┘        └┘            └──┘          └────
pid       └──┘        └┘            └──┘              
st     └─────────────┘└────────────┘└──────────┘└──────
2070  
src  
typ  
doc  
txt  
par  
pid  
st   
2071  lemma rel_join {s t} (h : rel (rel r) s t) : rel r s.join t.join :=
id                             └─┘  └─┘        └─┘  └───┘ └───┘
src                            └─┘  └─┘           └─┘    └───┘  └───┘
typ                            └─┘  └─┘        └─┘  └───┘ └───┘
doc                            └─┘  └─┘           └─┘    └───┘  └───┘
2072  begin
st   └─────
2073    induction h,
id               
src    └────────┘
typ    └────────┘
doc    └────────┘
txt    └────────┘
par    └────────┘
pid             
st   ────────────┘└─
2074    case rel.zero { simp },
src    └──────────────┘└───┘
typ    └──────────────┘└───┘
doc    └──────────────┘└───┘
txt    └──────────────┘└───┘
par    └──────────────┘└───┘
pid        └───────┘└──────┘
st   ────────────────┘└────┘└┘
2075    case rel.cons : a b s t hab hst ih { simpa using hab.add ih }
id                                                      └─────┘ └┘
src    └───────────────────────────────────┘└──────────┘└─────┘  └┘
typ    └───────────────────────────────────┘└──────────┘└─────┘└┘└┘
doc    └───────────────────────────────────┘└──────────┘         └┘
txt    └───────────────────────────────────┘└──────────┘         └┘
par    └───────────────────────────────────┘└──────────┘         └┘
pid        └───────┘└───────────────────┘└─────────────┘         └┘
st   ─────────────────────────────────────┘└──────────────────────┘
2076  end
st   └─┘
2077  
2078  lemma rel_map {p : γ → δ → Prop} {s t} {f : α → γ} {g : β → δ} (h : (r ⇒ p) f g) (hst : rel r s t) :
id                                                                                └─┘   
src                                                                                         └─┘
typ                                                                               └─┘   
doc                                                                                          └─┘
2079    rel p (s.map f) (t.map g) :=
id     └─┘   └──┘    └──┘ 
src    └─┘     └──┘      └──┘
typ    └─┘   └──┘    └──┘ 
doc    └─┘     └──┘      └──┘
2080  by rw [rel_map_left, rel_map_right]; exact hst.mono h
id          └──────────┘  └───────────┘         └──────┘ 
src     └──┘└──────────┘└┘└───────────┘  └────┘└──────┘ 
typ     └──┘└──────────┘└┘└───────────┘  └────┘└──────┘
doc     └──┘            └┘               └────┘         
txt     └──┘            └┘               └────┘         
par     └──┘            └┘               └────┘         
pid       └┘            └┘                             
st     └───────────────┘└─────────────┘└──────────────────
2081  
src  
typ  
doc  
txt  
par  
pid  
st   
2082  lemma rel_bind {p : γ → δ → Prop} {s t} {f : α → multiset γ} {g : β → multiset δ}
id                                                 └──────┘           └──────┘ 
src                                                   └──────┘             └──────┘
typ                                                └──────┘           └──────┘ 
doc                                                   └──────┘             └──────┘
2083    (h : (r ⇒ rel p) f g) (hst : rel r s t) :
id             └─┘             └─┘   
src             └─┘                └─┘
typ            └─┘             └─┘   
doc              └─┘                └─┘
2084    rel p (s.bind f) (t.bind g) :=
id     └─┘   └───┘    └───┘ 
src    └─┘     └───┘      └───┘
typ    └─┘   └───┘    └───┘ 
doc    └─┘     └───┘      └───┘
2085  by apply rel_join; apply rel_map; assumption
id            └──────┘        └─────┘
src     └────┘└──────┘  └────┘└─────┘  └──────────
typ     └────┘└──────┘  └────┘└─────┘  └──────────
doc     └────┘          └────┘         └──────────
txt     └────┘          └────┘         └──────────
par     └────┘          └────┘         └──────────
pid                                            
st     └──────────────────────────────────────────
2086  
src  
typ  
doc  
txt  
par  
pid  
st   
2087  lemma card_eq_card_of_rel {r : α → β → Prop} {s : multiset α} {t : multiset β} (h : rel r s t) :
id                                                   └──────┘        └──────┘        └─┘   
src                                                    └──────┘         └──────┘         └─┘
typ                                                  └──────┘        └──────┘        └─┘   
doc                                                    └──────┘         └──────┘         └─┘
2088    card s = card t :=
id     └──┘   └──┘ 
src    └──┘    └──┘
typ    └──┘   └──┘ 
doc    └──┘     └──┘
2089  by induction h; simp [*]
id                
src     └────────┘   └────────
typ     └────────┘  └────────
doc     └────────┘   └────────
txt     └────────┘   └────────
par     └────────┘   └────────
pid                     └─┘
st     └──────────────────────
2090  
src  
typ  
doc  
txt  
par  
pid  
st   
2091  lemma exists_mem_of_rel_of_mem {r : α → β → Prop} {s : multiset α} {t : multiset β} (h : rel r s t) :
id                                                        └──────┘        └──────┘        └─┘   
src                                                         └──────┘         └──────┘         └─┘
typ                                                       └──────┘        └──────┘        └─┘   
doc                                                         └──────┘         └──────┘         └─┘
2092    ∀ {a : α} (ha : a ∈ s), ∃ b ∈ t, r a b :=
id                                
src                                 
typ                               
2093  begin
st   └─────
2094    induction h with x y s t hxy hst ih,
id               
src    └────────┘ └──────────────────────┘
typ    └────────┘└──────────────────────┘
doc    └────────┘ └──────────────────────┘
txt    └────────┘ └──────────────────────┘
par    └────────┘ └──────────────────────┘
pid              └─────────────────────┘
st   ────────────────────────────────────┘└─
2095    { simp },
src      └───┘
typ      └───┘
doc      └───┘
txt      └───┘
par      └───┘
pid          
st   ───┘└───┘└┘
2096    { assume a ha,
src      └─────────┘
typ      └─────────┘
doc      └─────────┘
txt      └─────────┘
par      └─────────┘
pid      └─────────┘
st   ──────────────┘└─
2097      cases mem_cons.1 ha with ha ha,
id             └──────┘   └┘
src      └────┘└──────┘└─┘  └─────────┘
typ      └────┘└──────┘└─┘└┘└─────────┘
doc      └────┘        └─┘  └─────────┘
txt      └────┘        └─┘  └─────────┘
par      └────┘        └─┘  └─────────┘
pid                   └─┘  └─────────┘
st   ─────────────────────────────────┘└─
2098      { exact ⟨y, mem_cons_self _ _, ha.symm ▸ hxy⟩ },
id                  └───────────┘      └─────┘  └─┘
src        └────┘  └┘└───────────┘└────┘└─────┘   └┘
typ        └────┘ └┘└───────────┘└────┘└─────┘└─┘└┘
doc        └────┘  └┘             └────┘           └┘
txt        └────┘  └┘             └────┘           └┘
par        └────┘  └┘             └────┘           └┘
pid               └┘             └────┘           
st   ─────┘└──────────────────────────────────────────┘└┘
2099      { rcases ih ha with ⟨b, hbt, hab⟩,
id                └┘ └┘
src        └─────┘    └─────────────────┘
typ        └─────┘└┘└┘└─────────────────┘
doc        └─────┘    └─────────────────┘
txt        └─────┘    └─────────────────┘
par        └─────┘    └─────────────────┘
pid                  └─────────────────┘
st   ────────────────────────────────────┘└─
2100        exact ⟨b, mem_cons.2 (or.inr hbt), hab⟩ } }
id                  └──────┘    └────┘ └─┘   └─┘
src        └────┘  └┘└──────┘└─┘ └────┘   └─┘   └┘
typ        └────┘ └┘└──────┘└─┘ └────┘└─┘└─┘└─┘└┘
doc        └────┘  └┘        └─┘          └─┘   └┘
txt        └────┘  └┘        └─┘          └─┘   └┘
par        └────┘  └┘        └─┘          └─┘   └┘
pid               └┘        └─┘          └─┘   
st   ─────────────────────────────────────────────┘└───
2101  end
st   ──┘
2102  
2103  end rel
2104  
2105  section map
2106  
2107  theorem map_eq_map {f : α → β} (hf : function.injective f) {s t : multiset α} :
id                                      └────────────────┘          └──────┘ 
src                                       └────────────────┘           └──────┘
typ                                     └────────────────┘          └──────┘ 
doc                                                                    └──────┘
2108    s.map f = t.map f ↔ s = t :=
id     └──┘   └──┘     
src     └──┘     └──┘      
typ    └──┘   └──┘     
doc     └──┘      └──┘
2109  by rw [← rel_eq, ← rel_eq, rel_map_left, rel_map_right]; simp [hf.eq_iff]
id            └────┘    └────┘  └──────────┘  └───────────┘
src     └────┘└────┘└──┘└────┘└┘└──────────┘└┘└───────────┘  └────┘         └─
typ     └────┘└────┘└──┘└────┘└┘└──────────┘└┘└───────────┘  └────┘└───────┘└─
doc     └────┘      └──┘      └┘            └┘               └────┘         └─
txt     └────┘      └──┘      └┘            └┘               └────┘         └─
par     └────┘      └──┘      └┘            └┘               └────┘         └─
pid       └──┘      └──┘      └┘            └┘                            
st     └───────────┘└────────┘└────────────┘└─────────────┘└──────────────────
2110  
src  
typ  
doc  
txt  
par  
pid  
st   
2111  theorem injective_map {f : α → β} (hf : function.injective f) :
id                                         └────────────────┘ 
src                                          └────────────────┘
typ                                        └────────────────┘ 
2112    function.injective (multiset.map f) :=
id     └────────────────┘  └──────────┘ 
src    └────────────────┘  └──────────┘
typ    └────────────────┘  └──────────┘ 
doc                        └──────────┘
2113  assume x y, (map_eq_map hf).1
id              └────────┘ └┘ 
src               └────────┘    
typ             └────────┘ └┘ 
2114  
2115  end map
2116  
2117  section quot
2118  
2119  theorem map_mk_eq_map_mk_of_rel {r : α → α → Prop} {s t : multiset α} (hst : s.rel r t) :
id                                                           └──────┘          └──┘  
src                                                            └──────┘            └──┘
typ                                                          └──────┘          └──┘  
doc                                                            └──────┘            └──┘
2120   s.map (quot.mk r) = t.map (quot.mk r) :=
id    └──┘  └─────┘    └──┘  └─────┘ 
src    └──┘               └──┘
typ   └──┘  └─────┘    └──┘  └─────┘ 
doc    └──┘                └──┘
2121  rel.rec_on hst rfl $ assume a b s t hab hst ih, by simp [ih, quot.sound hab]
id   └────────┘ └─┘ └─┘              └─┘ └─┘ └┘           └┘  └────────┘ └─┘
src  └────────┘     └─┘                                 └────┘  └┘└────────┘   └─
typ  └────────┘ └─┘ └─┘              └─┘ └─┘ └┘     └────┘└┘└┘└────────┘└─┘└─
doc                                                     └────┘  └┘             └─
txt                                                     └────┘  └┘             └─
par                                                     └────┘  └┘             └─
pid                                                           └┘             
st                                                     └──────────────────────────
2122  
src  
typ  
doc  
txt  
par  
pid  
st   
2123  theorem exists_multiset_eq_map_quot_mk {r : α → α → Prop} (s : multiset (quot r)) :
id                                                                └──────┘  └──┘ 
src                                                                 └──────┘
typ                                                               └──────┘  └──┘ 
doc                                                                 └──────┘
2124    ∃t:multiset α, s = t.map (quot.mk r) :=
id       └──────┘    └──┘  └─────┘ 
src      └──────┘       └──┘
typ      └──────┘    └──┘  └─────┘ 
doc       └──────┘         └──┘
2125  multiset.induction_on s ⟨0, rfl⟩ $
id   └───────────────────┘      └─┘
src  └───────────────────┘       └─┘
typ  └───────────────────┘      └─┘
2126    assume a s ⟨t, ht⟩, quot.induction_on a $ assume a, ht.symm ▸ ⟨a::t, (map_cons _ _ _).symm⟩
id                └┘   └───────────────┘               └───┘   └┘    └──────┘       └──┘
src                        └───────────────┘                 └───┘    └┘    └──────┘       └──┘
typ               └┘   └───────────────┘               └───┘   └┘    └──────┘       └──┘
doc                                                                    └┘
2127  
2128  theorem induction_on_multiset_quot
2129    {r : α → α → Prop} {p : multiset (quot r) → Prop} (s : multiset (quot r)) :
id                           └──────┘  └──┘                └──────┘  └──┘ 
src                            └──────┘                       └──────┘
typ                          └──────┘  └──┘                └──────┘  └──┘ 
doc                            └──────┘                       └──────┘
2130    (∀s:multiset α, p (s.map (quot.mk r))) → p s :=
id        └──────┘     └──┘  └─────┘        
src        └──────┘        └──┘
typ       └──────┘     └──┘  └─────┘        
doc        └──────┘        └──┘
2131  match s, exists_multiset_eq_map_quot_mk s with _, ⟨t, rfl⟩ := assume h, h _ end
id           └────────────────────────────┘              └─┘              
src           └────────────────────────────┘               └─┘
typ          └────────────────────────────┘              └─┘              
2132  
2133  end quot
2134  
2135  /- disjoint -/
2136  
2137  /-- `disjoint s t` means that `s` and `t` have no elements in common. -/
2138  def disjoint (s t : multiset α) : Prop := ∀ ⦃a⦄, a ∈ s → a ∈ t → false
id                       └──────┘                             └───┘
src                      └──────┘                                   └───┘
typ                      └──────┘                             └───┘
doc                      └──────┘
2139  
2140  @[simp] theorem coe_disjoint (l₁ l₂ : list α) : @disjoint α l₁ l₂ ↔ l₁.disjoint l₂ := iff.rfl
id                                         └──┘      └──────┘  └┘ └┘  └┘└───────┘ └┘    └─────┘
src                                        └──┘       └──────┘            └───────┘       └─────┘
typ                                        └──┘      └──────┘  └┘ └┘  └┘└───────┘ └┘    └─────┘
doc    └──┘                                           └──────┘             └───────┘
2141  
2142  theorem disjoint.symm {s t : multiset α} (d : disjoint s t) : disjoint t s
id                                └──────┘        └──────┘      └──────┘  
src                               └──────┘         └──────┘        └──────┘
typ                               └──────┘        └──────┘      └──────┘  
doc                               └──────┘         └──────┘        └──────┘
2143  | a i₂ i₁ := d i₁ i₂
id       └┘ └┘    
typ      └┘ └┘    
2144  
2145  @[simp] theorem disjoint_comm {s t : multiset α} : disjoint s t ↔ disjoint t s :=
id                                        └──────┘     └──────┘    └──────┘  
src                                       └──────┘      └──────┘      └──────┘
typ                                       └──────┘     └──────┘    └──────┘  
doc    └──┘                               └──────┘      └──────┘       └──────┘
2146  ⟨disjoint.symm, disjoint.symm⟩
id    └───────────┘  └───────────┘
src   └───────────┘  └───────────┘
typ   └───────────┘  └───────────┘
2147  
2148  theorem disjoint_left {s t : multiset α} : disjoint s t ↔ ∀ {a}, a ∈ s → a ∉ t := iff.rfl
id                                └──────┘     └──────┘                     └─────┘
src                               └──────┘      └──────┘                            └─────┘
typ                               └──────┘     └──────┘                     └─────┘
doc                               └──────┘      └──────┘
2149  
2150  theorem disjoint_right {s t : multiset α} : disjoint s t ↔ ∀ {a}, a ∈ t → a ∉ s :=
id                                 └──────┘     └──────┘                 
src                                └──────┘      └──────┘                      
typ                                └──────┘     └──────┘                 
doc                                └──────┘      └──────┘
2151  disjoint_comm
id   └───────────┘
src  └───────────┘
typ  └───────────┘
2152  
2153  theorem disjoint_iff_ne {s t : multiset α} : disjoint s t ↔ ∀ a ∈ s, ∀ b ∈ t, a ≠ b :=
id                                  └──────┘     └──────┘                    
src                                 └──────┘      └──────┘                          
typ                                 └──────┘     └──────┘                    
doc                                 └──────┘      └──────┘
2154  by simp [disjoint_left, imp_not_comm]
id            └───────────┘  └──────────┘
src     └────┘└───────────┘└┘└──────────┘└─
typ     └────┘└───────────┘└┘└──────────┘└─
doc     └────┘             └┘            └─
txt     └────┘             └┘            └─
par     └────┘             └┘            └─
pid                      └┘            
st     └───────────────────────────────────
2155  
src  
typ  
doc  
txt  
par  
pid  
st   
2156  theorem disjoint_of_subset_left {s t u : multiset α} (h : s ⊆ u) (d : disjoint u t) : disjoint s t
id                                            └──────┘                 └──────┘      └──────┘  
src                                           └──────┘                    └──────┘        └──────┘
typ                                           └──────┘                 └──────┘      └──────┘  
doc                                           └──────┘                     └──────┘        └──────┘
2157  | x m₁ := d (h m₁)
id       └┘      
typ      └┘      
2158  
2159  theorem disjoint_of_subset_right {s t u : multiset α} (h : t ⊆ u) (d : disjoint s u) : disjoint s t
id                                             └──────┘                 └──────┘      └──────┘  
src                                            └──────┘                    └──────┘        └──────┘
typ                                            └──────┘                 └──────┘      └──────┘  
doc                                            └──────┘                     └──────┘        └──────┘
2160  | x m m₁ := d m (h m₁)
id        └┘        
typ       └┘        
2161  
2162  theorem disjoint_of_le_left {s t u : multiset α} (h : s ≤ u) : disjoint u t → disjoint s t :=
id                                        └──────┘              └──────┘     └──────┘  
src                                       └──────┘                 └──────┘       └──────┘
typ                                       └──────┘              └──────┘     └──────┘  
doc                                       └──────┘                  └──────┘       └──────┘
2163  disjoint_of_subset_left (subset_of_le h)
id   └─────────────────────┘  └──────────┘ 
src  └─────────────────────┘  └──────────┘
typ  └─────────────────────┘  └──────────┘ 
2164  
2165  theorem disjoint_of_le_right {s t u : multiset α} (h : t ≤ u) : disjoint s u → disjoint s t :=
id                                         └──────┘              └──────┘     └──────┘  
src                                        └──────┘                 └──────┘       └──────┘
typ                                        └──────┘              └──────┘     └──────┘  
doc                                        └──────┘                  └──────┘       └──────┘
2166  disjoint_of_subset_right (subset_of_le h)
id   └──────────────────────┘  └──────────┘ 
src  └──────────────────────┘  └──────────┘
typ  └──────────────────────┘  └──────────┘ 
2167  
2168  @[simp] theorem zero_disjoint (l : multiset α) : disjoint 0 l
id                                      └──────┘     └──────┘   
src                                     └──────┘      └──────┘
typ                                     └──────┘     └──────┘   
doc    └──┘                             └──────┘      └──────┘
2169  | a := (not_mem_nil a).elim
id          └─────────┘   └──┘
src          └─────────┘   └──┘
typ         └─────────┘   └──┘
2170  
2171  @[simp] theorem singleton_disjoint {l : multiset α} {a : α} : disjoint (a::0) l ↔ a ∉ l :=
id                                           └──────┘            └──────┘  └┘       
src                                          └──────┘              └──────┘   └┘        
typ                                          └──────┘            └──────┘  └┘       
doc    └──┘                                  └──────┘              └──────┘   └┘
2172  by simp [disjoint]; refl
id            └──────┘
src     └────┘└──────┘  └────
typ     └────┘└──────┘  └────
doc     └────┘└──────┘  └────
txt     └────┘          └────
par     └────┘          └────
pid                       
st     └──────────────────────
2173  
src  
typ  
doc  
txt  
par  
pid  
st   
2174  @[simp] theorem disjoint_singleton {l : multiset α} {a : α} : disjoint l (a::0) ↔ a ∉ l :=
id                                           └──────┘            └──────┘   └┘      
src                                          └──────┘              └──────┘     └┘      
typ                                          └──────┘            └──────┘   └┘      
doc    └──┘                                  └──────┘              └──────┘     └┘
2175  by rw disjoint_comm; simp
id         └───────────┘
src     └─┘└───────────┘  └────
typ     └─┘└───────────┘  └────
doc     └─┘               └────
txt     └─┘               └────
par     └─┘               └────
pid                          
st     └───────────────────────
2176  
src  
typ  
doc  
txt  
par  
pid  
st   
2177  @[simp] theorem disjoint_add_left {s t u : multiset α} :
id                                              └──────┘ 
src                                             └──────┘
typ                                             └──────┘ 
doc    └──┘                                     └──────┘
2178    disjoint (s + t) u ↔ disjoint s u ∧ disjoint t u :=
id     └──────┘        └──────┘    └──────┘  
src    └──────┘           └──────┘      └──────┘
typ    └──────┘        └──────┘    └──────┘  
doc    └──────┘             └──────┘       └──────┘
2179  by simp [disjoint, or_imp_distrib, forall_and_distrib]
id            └──────┘  └────────────┘  └────────────────┘
src     └────┘└──────┘└┘└────────────┘└┘└────────────────┘└─
typ     └────┘└──────┘└┘└────────────┘└┘└────────────────┘└─
doc     └────┘└──────┘└┘              └┘                  └─
txt     └────┘        └┘              └┘                  └─
par     └────┘        └┘              └┘                  └─
pid                 └┘              └┘                  
st     └────────────────────────────────────────────────────
2180  
src  
typ  
doc  
txt  
par  
pid  
st   
2181  @[simp] theorem disjoint_add_right {s t u : multiset α} :
id                                               └──────┘ 
src                                              └──────┘
typ                                              └──────┘ 
doc    └──┘                                      └──────┘
2182    disjoint s (t + u) ↔ disjoint s t ∧ disjoint s u :=
id     └──────┘        └──────┘    └──────┘  
src    └──────┘           └──────┘      └──────┘
typ    └──────┘        └──────┘    └──────┘  
doc    └──────┘             └──────┘       └──────┘
2183  disjoint_comm.trans $ by simp [disjoint_append_left]
id   └───────────┘└────┘            └──────────────────┘
src  └───────────┘└────┘      └────┘└──────────────────┘└─
typ  └───────────┘└────┘      └────┘└──────────────────┘└─
doc                           └────┘                    └─
txt                           └────┘                    └─
par                           └────┘                    └─
pid                                                   
st                           └────────────────────────────
2184  
src  
typ  
doc  
txt  
par  
pid  
st   
2185  @[simp] theorem disjoint_cons_left {a : α} {s t : multiset α} :
id                                                    └──────┘ 
src                                                    └──────┘
typ                                                   └──────┘ 
doc    └──┘                                            └──────┘
2186    disjoint (a::s) t ↔ a ∉ t ∧ disjoint s t :=
id     └──────┘  └┘        └──────┘  
src    └──────┘   └┘            └──────┘
typ    └──────┘  └┘        └──────┘  
doc    └──────┘   └┘               └──────┘
2187  (@disjoint_add_left _ (a::0) s t).trans $ by simp
id     └───────────────┘    └┘     └───┘
src    └───────────────┘     └┘       └───┘       └────
typ    └───────────────┘    └┘     └───┘       └────
doc                          └┘                   └────
txt                                               └────
par                                               └────
pid                                                   
st                                               └─────
2188  
src  
typ  
doc  
txt  
par  
pid  
st   
2189  @[simp] theorem disjoint_cons_right {a : α} {s t : multiset α} :
id                                                     └──────┘ 
src                                                     └──────┘
typ                                                    └──────┘ 
doc    └──┘                                             └──────┘
2190    disjoint s (a::t) ↔ a ∉ s ∧ disjoint s t :=
id     └──────┘   └┘       └──────┘  
src    └──────┘     └┘          └──────┘
typ    └──────┘   └┘       └──────┘  
doc    └──────┘     └┘             └──────┘
2191  disjoint_comm.trans $ by simp [disjoint_cons_left]
id   └───────────┘└────┘            └────────────────┘
src  └───────────┘└────┘      └────┘└────────────────┘└─
typ  └───────────┘└────┘      └────┘└────────────────┘└─
doc                           └────┘                  └─
txt                           └────┘                  └─
par                           └────┘                  └─
pid                                                 
st                           └──────────────────────────
2192  
src  
typ  
doc  
txt  
par  
pid  
st   
2193  theorem inter_eq_zero_iff_disjoint [decidable_eq α] {s t : multiset α} : s ∩ t = 0 ↔ disjoint s t :=
id                                       └──────────┘          └──────┘            └──────┘  
src                                      └──────────┘           └──────┘               └──────┘
typ                                      └──────────┘          └──────┘            └──────┘  
doc                                                             └──────┘                  └──────┘
2194  by rw ← subset_zero; simp [subset_iff, disjoint]
id           └─────────┘        └────────┘  └──────┘
src     └───┘└─────────┘  └────┘└────────┘└┘└──────┘└─
typ     └───┘└─────────┘  └────┘└────────┘└┘└──────┘└─
doc     └───┘             └────┘          └┘└──────┘└─
txt     └───┘             └────┘          └┘        └─
par     └───┘             └────┘          └┘        └─
pid       └─┘                           └┘        
st     └──────────────────────────────────────────────
2195  
src  
typ  
doc  
txt  
par  
pid  
st   
2196  @[simp] theorem disjoint_union_left [decidable_eq α] {s t u : multiset α} :
id                                        └──────────┘            └──────┘ 
src                                       └──────────┘             └──────┘
typ                                       └──────────┘            └──────┘ 
doc    └──┘                                                        └──────┘
2197    disjoint (s ∪ t) u ↔ disjoint s u ∧ disjoint t u :=
id     └──────┘        └──────┘    └──────┘  
src    └──────┘           └──────┘      └──────┘
typ    └──────┘        └──────┘    └──────┘  
doc    └──────┘             └──────┘       └──────┘
2198  by simp [disjoint, or_imp_distrib, forall_and_distrib]
id            └──────┘  └────────────┘  └────────────────┘
src     └────┘└──────┘└┘└────────────┘└┘└────────────────┘└─
typ     └────┘└──────┘└┘└────────────┘└┘└────────────────┘└─
doc     └────┘└──────┘└┘              └┘                  └─
txt     └────┘        └┘              └┘                  └─
par     └────┘        └┘              └┘                  └─
pid                 └┘              └┘                  
st     └────────────────────────────────────────────────────
2199  
src  
typ  
doc  
txt  
par  
pid  
st   
2200  @[simp] theorem disjoint_union_right [decidable_eq α] {s t u : multiset α} :
id                                         └──────────┘            └──────┘ 
src                                        └──────────┘             └──────┘
typ                                        └──────────┘            └──────┘ 
doc    └──┘                                                         └──────┘
2201    disjoint s (t ∪ u) ↔ disjoint s t ∧ disjoint s u :=
id     └──────┘        └──────┘    └──────┘  
src    └──────┘           └──────┘      └──────┘
typ    └──────┘        └──────┘    └──────┘  
doc    └──────┘             └──────┘       └──────┘
2202  by simp [disjoint, or_imp_distrib, forall_and_distrib]
id            └──────┘  └────────────┘  └────────────────┘
src     └────┘└──────┘└┘└────────────┘└┘└────────────────┘└─
typ     └────┘└──────┘└┘└────────────┘└┘└────────────────┘└─
doc     └────┘└──────┘└┘              └┘                  └─
txt     └────┘        └┘              └┘                  └─
par     └────┘        └┘              └┘                  └─
pid                 └┘              └┘                  
st     └────────────────────────────────────────────────────
2203  
src  
typ  
doc  
txt  
par  
pid  
st   
2204  lemma disjoint_map_map {f : α → γ} {g : β → γ} {s : multiset α} {t : multiset β} :
id                                                   └──────┘        └──────┘ 
src                                                      └──────┘         └──────┘
typ                                                  └──────┘        └──────┘ 
doc                                                      └──────┘         └──────┘
2205    disjoint (s.map f) (t.map g) ↔ (∀a∈s, ∀b∈t, f a ≠ g b) :=
id     └──────┘  └──┘    └──┘                 
src    └──────┘   └──┘     └──┘                      
typ    └──────┘  └──┘    └──┘                 
doc    └──────┘   └──┘      └──┘
2206  begin
st   └─────
2207    simp [disjoint],
id           └──────┘
src    └────┘└──────┘
typ    └────┘└──────┘
doc    └────┘└──────┘
txt    └────┘        
par    └────┘        
pid                
st   ────────────────┘└─
2208    split,
src    └───┘
typ    └───┘
doc    └───┘
txt    └───┘
par    └───┘
st   ──────┘└─
2209    from assume h a ha b hb eq, h _ ha rfl _ hb eq.symm,
id                                        └─┘        └───┘
src    └───┘      └───────────────┘ └─┘  └─┘└─┘    └───┘
typ    └───┘      └───────────────┘ └─┘  └─┘└─┘    └───┘
doc    └───┘      └───────────────┘ └─┘     └─┘  
txt    └───┘      └───────────────┘ └─┘     └─┘  
par    └───┘      └───────────────┘ └─┘     └─┘  
pid    └───┘      └───────────────┘ └─┘     └─┘  
st   ────────────────────────────────────────────────────┘└─
2210    from assume h c a ha eq₁ b hb eq₂, h _ ha _ hb (eq₂.symm ▸ eq₁)
id                                                              
src    └───┘      └──────────────────────┘ └─┘  └─┘              └┘
typ    └───┘      └──────────────────────┘ └─┘  └─┘              └┘
doc    └───┘      └──────────────────────┘ └─┘  └─┘               └┘
txt    └───┘      └──────────────────────┘ └─┘  └─┘               └┘
par    └───┘      └──────────────────────┘ └─┘  └─┘               └┘
pid    └───┘      └──────────────────────┘ └─┘  └─┘               
st   ─────────────────────────────────────────────────────────────────┘
2211  end
st   └─┘
2212  
2213  /-- `pairwise r m` states that there exists a list of the elements s.t. `r` holds pairwise on this list. -/
2214  def pairwise (r : α → α → Prop) (m : multiset α) : Prop :=
id                                      └──────┘ 
src                                       └──────┘
typ                                     └──────┘ 
doc                                       └──────┘
2215  ∃l:list α, m = l ∧ l.pairwise r
id     └──┘      └───────┘ 
src    └──┘          └───────┘
typ    └──┘      └───────┘ 
doc                      └───────┘
2216  
2217  lemma pairwise_coe_iff_pairwise {r : α → α → Prop} (hr : symmetric r) {l : list α} :
id                                                          └───────┘        └──┘ 
src                                                           └───────┘         └──┘
typ                                                         └───────┘        └──┘ 
2218    multiset.pairwise r l ↔ l.pairwise r :=
id     └───────────────┘    └───────┘ 
src    └───────────────┘       └───────┘
typ    └───────────────┘    └───────┘ 
doc    └───────────────┘        └───────┘
2219  iff.intro
id   └───────┘
src  └───────┘
typ  └───────┘
2220    (assume ⟨l', eq, h⟩, (list.perm_pairwise hr (quotient.exact eq)).2 h)
id                 └┘      └────────────────┘ └┘  └────────────┘     
src                 └┘       └────────────────┘     └────────────┘     
typ                └┘      └────────────────┘ └┘  └────────────┘     
2221    (assume h, ⟨l, rfl, h⟩)
id                  └─┘  
src                   └─┘
typ                 └─┘  
2222  
2223  /- nodup -/
2224  
2225  /-- `nodup s` means that `s` has no duplicates, i.e. the multiplicity of
2226    any element is at most 1. -/
2227  def nodup (s : multiset α) : Prop :=
id                  └──────┘ 
src                 └──────┘
typ                 └──────┘ 
doc                 └──────┘
2228  quot.lift_on s nodup (λ s t p, propext $ perm_nodup p)
id   └──────────┘  └───┘        └─────┘   └────────┘ 
src  └──────────┘   └───┘           └─────┘   └────────┘
typ  └──────────┘  └───┘        └─────┘   └────────┘ 
doc                 └───┘
2229  
2230  @[simp] theorem coe_nodup {l : list α} : @nodup α l ↔ l.nodup := iff.rfl
id                                  └──┘      └───┘    └────┘    └─────┘
src                                 └──┘       └───┘       └────┘    └─────┘
typ                                 └──┘      └───┘    └────┘    └─────┘
doc    └──┘                                    └───┘        └────┘
2231  
2232  @[simp] theorem forall_mem_ne {a : α} {l : list α} : (∀ (a' : α), a' ∈ l → ¬a = a') ↔ a ∉ l :=
id                                             └──┘                 └┘       └┘     
src                                             └──┘                                     
typ                                            └──┘                 └┘       └┘     
doc    └──┘
2233  ⟨λ h m, h _ m rfl, λ h a' m e, h (e.symm ▸ m)⟩
id             └─┘     └┘      └───┘  
src                └─┘                  └───┘ 
typ            └─┘     └┘      └───┘  
2234  
2235  @[simp] theorem nodup_zero : @nodup α 0 := pairwise.nil
id                                 └───┘       └──────────┘
src                                └───┘        └──────────┘
typ                                └───┘       └──────────┘
doc    └──┘                        └───┘
2236  
2237  @[simp] theorem nodup_cons {a : α} {s : multiset α} : nodup (a::s) ↔ a ∉ s ∧ nodup s :=
id                                          └──────┘     └───┘  └┘       └───┘ 
src                                          └──────┘      └───┘   └┘          └───┘
typ                                         └──────┘     └───┘  └┘       └───┘ 
doc    └──┘                                  └──────┘      └───┘   └┘             └───┘
2238  quot.induction_on s $ λ l, nodup_cons
id   └───────────────┘        └────────┘
src  └───────────────┘          └────────┘
typ  └───────────────┘        └────────┘
2239  
2240  theorem nodup_cons_of_nodup {a : α} {s : multiset α} (m : a ∉ s) (n : nodup s) : nodup (a::s) :=
id                                           └──────┘                 └───┘     └───┘  └┘
src                                           └──────┘                    └───┘      └───┘   └┘
typ                                          └──────┘                 └───┘     └───┘  └┘
doc                                           └──────┘                     └───┘      └───┘   └┘
2241  nodup_cons.2 ⟨m, n⟩
id   └────────┘     
src  └────────┘
typ  └────────┘     
2242  
2243  theorem nodup_singleton : ∀ a : α, nodup (a::0) := nodup_singleton
id                                     └───┘  └┘      └─────────────┘
src                                     └───┘   └┘      └─────────────┘
typ                                    └───┘  └┘      └─────────────┘
doc                                     └───┘   └┘
2244  
2245  theorem nodup_of_nodup_cons {a : α} {s : multiset α} (h : nodup (a::s)) : nodup s :=
id                                           └──────┘        └───┘  └┘     └───┘ 
src                                           └──────┘         └───┘   └┘      └───┘
typ                                          └──────┘        └───┘  └┘     └───┘ 
doc                                           └──────┘         └───┘   └┘      └───┘
2246  (nodup_cons.1 h).2
id    └────────┘   
src   └────────┘    
typ   └────────┘   
2247  
2248  theorem not_mem_of_nodup_cons {a : α} {s : multiset α} (h : nodup (a::s)) : a ∉ s :=
id                                             └──────┘        └───┘  └┘       
src                                             └──────┘         └───┘   └┘        
typ                                            └──────┘        └───┘  └┘       
doc                                             └──────┘         └───┘   └┘
2249  (nodup_cons.1 h).1
id    └────────┘   
src   └────────┘    
typ   └────────┘   
2250  
2251  theorem nodup_of_le {s t : multiset α} (h : s ≤ t) : nodup t → nodup s :=
id                              └──────┘              └───┘    └───┘ 
src                             └──────┘                 └───┘     └───┘
typ                             └──────┘              └───┘    └───┘ 
doc                             └──────┘                  └───┘     └───┘
2252  le_induction_on h $ λ l₁ l₂, nodup_of_sublist
id   └─────────────┘      └┘ └┘  └──────────────┘
src  └─────────────┘              └──────────────┘
typ  └─────────────┘      └┘ └┘  └──────────────┘
2253  
2254  theorem not_nodup_pair : ∀ a : α, ¬ nodup (a::a::0) := not_nodup_pair
id                                     └───┘  └┘└┘      └────────────┘
src                                     └───┘   └┘ └┘      └────────────┘
typ                                    └───┘  └┘└┘      └────────────┘
doc                                      └───┘   └┘ └┘
2255  
2256  theorem nodup_iff_le {s : multiset α} : nodup s ↔ ∀ a : α, ¬ a::a::0 ≤ s :=
id                             └──────┘     └───┘            └┘└┘   
src                            └──────┘      └───┘               └┘ └┘  
typ                            └──────┘     └───┘            └┘└┘   
doc                            └──────┘      └───┘                 └┘ └┘
2257  quot.induction_on s $ λ l, nodup_iff_sublist.trans $ forall_congr $ λ a,
id   └───────────────┘        └───────────────┘└────┘   └──────────┘     
src  └───────────────┘          └───────────────┘└────┘   └──────────┘
typ  └───────────────┘        └───────────────┘└────┘   └──────────┘     
2258  not_congr (@repeat_le_coe _ a 2 _).symm
id   └───────┘   └───────────┘        └──┘
src  └───────┘   └───────────┘         └──┘
typ  └───────┘   └───────────┘        └──┘
2259  
2260  theorem nodup_iff_count_le_one [decidable_eq α] {s : multiset α} : nodup s ↔ ∀ a, count a s ≤ 1 :=
id                                   └──────────┘        └──────┘     └───┘       └───┘   
src                                  └──────────┘         └──────┘      └───┘         └───┘     
typ                                  └──────────┘        └──────┘     └───┘       └───┘   
doc                                                       └──────┘      └───┘          └───┘
2261  quot.induction_on s $ λ l, nodup_iff_count_le_one
id   └───────────────┘        └────────────────────┘
src  └───────────────┘          └────────────────────┘
typ  └───────────────┘        └────────────────────┘
2262  
2263  @[simp] theorem count_eq_one_of_mem [decidable_eq α] {a : α} {s : multiset α}
id                                        └──────────┘               └──────┘ 
src                                       └──────────┘                 └──────┘
typ                                       └──────────┘               └──────┘ 
doc    └──┘                                                            └──────┘
2264    (d : nodup s) (h : a ∈ s) : count a s = 1 :=
id          └───┘              └───┘   
src         └───┘                 └───┘     
typ         └───┘              └───┘   
doc         └───┘                  └───┘
2265  le_antisymm (nodup_iff_count_le_one.1 d a) (count_pos.2 h)
id   └─────────┘  └────────────────────┘      └───────┘  
src  └─────────┘  └────────────────────┘        └───────┘
typ  └─────────┘  └────────────────────┘      └───────┘  
2266  
2267  lemma pairwise_of_nodup {r : α → α → Prop} {s : multiset α} :
id                                                 └──────┘ 
src                                                  └──────┘
typ                                                └──────┘ 
doc                                                  └──────┘
2268    (∀a∈s, ∀b∈s, a ≠ b → r a b) → nodup s → pairwise r s :=
id                         └───┘    └──────┘  
src                                 └───┘     └──────┘
typ                        └───┘    └──────┘  
doc                                  └───┘     └──────┘
2269  quotient.induction_on s $ assume l h hl, ⟨l, rfl, hl.imp_of_mem $ assume a b ha hb, h a ha b hb⟩
id   └───────────────────┘             └┘     └─┘  └┘└─────────┘            └┘ └┘    └┘  └┘
src  └───────────────────┘                        └─┘    └─────────┘
typ  └───────────────────┘             └┘     └─┘  └┘└─────────┘            └┘ └┘    └┘  └┘
2270  
2271  lemma forall_of_pairwise {r : α → α → Prop} (H : symmetric r) {s : multiset α}
id                                                  └───────┘        └──────┘ 
src                                                   └───────┘         └──────┘
typ                                                 └───────┘        └──────┘ 
doc                                                                     └──────┘
2272     (hs : pairwise r s) : (∀a∈s, ∀b∈s, a ≠ b → r a b) :=
id            └──────┘                      
src           └──────┘                       
typ           └──────┘                      
doc           └──────┘
2273  let ⟨l, hl₁, hl₂⟩ := hs in hl₁.symm ▸ list.forall_of_pairwise H hl₂
id   └─┘     └─┘  └─┘     └┘       └───┘  └─────────────────────┘ 
src                                └───┘  └─────────────────────┘
typ  └─┘     └─┘  └─┘     └┘       └───┘  └─────────────────────┘ 
2274  
2275  theorem nodup_add {s t : multiset α} : nodup (s + t) ↔ nodup s ∧ nodup t ∧ disjoint s t :=
id                            └──────┘     └───┘       └───┘   └───┘   └──────┘  
src                           └──────┘      └───┘         └───┘    └───┘    └──────┘
typ                           └──────┘     └───┘       └───┘   └───┘   └──────┘  
doc                           └──────┘      └───┘           └───┘     └───┘     └──────┘
2276  quotient.induction_on₂ s t $ λ l₁ l₂, nodup_append
id   └────────────────────┘       └┘ └┘  └──────────┘
src  └────────────────────┘                └──────────┘
typ  └────────────────────┘       └┘ └┘  └──────────┘
2277  
2278  theorem disjoint_of_nodup_add {s t : multiset α} (d : nodup (s + t)) : disjoint s t :=
id                                        └──────┘        └───┘         └──────┘  
src                                       └──────┘         └───┘           └──────┘
typ                                       └──────┘        └───┘         └──────┘  
doc                                       └──────┘         └───┘            └──────┘
2279  (nodup_add.1 d).2.2
id    └───────┘    
src   └───────┘     
typ   └───────┘    
2280  
2281  theorem nodup_add_of_nodup {s t : multiset α} (d₁ : nodup s) (d₂ : nodup t) : nodup (s + t) ↔ disjoint s t :=
id                                     └──────┘         └───┘         └───┘     └───┘       └──────┘  
src                                    └──────┘          └───┘          └───┘      └───┘         └──────┘
typ                                    └──────┘         └───┘         └───┘     └───┘       └──────┘  
doc                                    └──────┘          └───┘          └───┘      └───┘           └──────┘
2282  by simp [nodup_add, d₁, d₂]
id            └───────┘  └┘  └┘
src     └────┘└───────┘└┘  └┘  └─
typ     └────┘└───────┘└┘└┘└┘└┘└─
doc     └────┘         └┘  └┘  └─
txt     └────┘         └┘  └┘  └─
par     └────┘         └┘  └┘  └─
pid                  └┘  └┘  
st     └─────────────────────────
2283  
src  
typ  
doc  
txt  
par  
pid  
st   
2284  theorem nodup_of_nodup_map (f : α → β) {s : multiset α} : nodup (map f s) → nodup s :=
id                                             └──────┘     └───┘  └─┘      └───┘ 
src                                              └──────┘      └───┘  └─┘        └───┘
typ                                            └──────┘     └───┘  └─┘      └───┘ 
doc                                              └──────┘      └───┘  └─┘        └───┘
2285  quot.induction_on s $ λ l, nodup_of_nodup_map f
id   └───────────────┘        └────────────────┘ 
src  └───────────────┘          └────────────────┘
typ  └───────────────┘        └────────────────┘ 
2286  
2287  theorem nodup_map_on {f : α → β} {s : multiset α} : (∀x∈s, ∀y∈s, f x = f y → x = y) →
id                                       └──────┘                       
src                                        └──────┘                                
typ                                      └──────┘                       
doc                                        └──────┘
2288    nodup s → nodup (map f s) :=
id     └───┘    └───┘  └─┘  
src    └───┘     └───┘  └─┘
typ    └───┘    └───┘  └─┘  
doc    └───┘     └───┘  └─┘
2289  quot.induction_on s $ λ l, nodup_map_on
id   └───────────────┘        └──────────┘
src  └───────────────┘          └──────────┘
typ  └───────────────┘        └──────────┘
2290  
2291  theorem nodup_map {f : α → β} {s : multiset α} (hf : function.injective f) : nodup s → nodup (map f s) :=
id                                    └──────┘         └────────────────┘     └───┘    └───┘  └─┘  
src                                     └──────┘          └────────────────┘      └───┘     └───┘  └─┘
typ                                   └──────┘         └────────────────┘     └───┘    └───┘  └─┘  
doc                                     └──────┘                                  └───┘     └───┘  └─┘
2292  nodup_map_on (λ x _ y _ h, hf h)
id   └──────────┘          └┘ 
src  └──────────┘
typ  └──────────┘          └┘ 
2293  
2294  theorem nodup_filter (p : α → Prop) [decidable_pred p] {s} : nodup s → nodup (filter p s) :=
id                                       └────────────┘         └───┘    └───┘  └────┘  
src                                       └────────────┘          └───┘     └───┘  └────┘
typ                                      └────────────┘         └───┘    └───┘  └────┘  
doc                                                               └───┘     └───┘  └────┘
2295  quot.induction_on s $ λ l, nodup_filter p
id   └───────────────┘        └──────────┘ 
src  └───────────────┘          └──────────┘
typ  └───────────────┘        └──────────┘ 
2296  
2297  @[simp] theorem nodup_attach {s : multiset α} : nodup (attach s) ↔ nodup s :=
id                                     └──────┘     └───┘  └────┘    └───┘ 
src                                    └──────┘      └───┘  └────┘     └───┘
typ                                    └──────┘     └───┘  └────┘    └───┘ 
doc    └──┘                            └──────┘      └───┘  └────┘      └───┘
2298  quot.induction_on s $ λ l, nodup_attach
id   └───────────────┘        └──────────┘
src  └───────────────┘          └──────────┘
typ  └───────────────┘        └──────────┘
2299  
2300  theorem nodup_pmap {p : α → Prop} {f : Π a, p a → β} {s : multiset α} {H}
id                                                        └──────┘ 
src                                                            └──────┘
typ                                                       └──────┘ 
doc                                                            └──────┘
2301    (hf : ∀ a ha b hb, f a ha = f b hb → a = b) : nodup s → nodup (pmap f s H) :=
id              └┘  └┘    └┘    └┘         └───┘    └───┘  └──┘   
src                                                └───┘     └───┘  └──┘
typ             └┘  └┘    └┘    └┘         └───┘    └───┘  └──┘   
doc                                                  └───┘     └───┘  └──┘
2302  quot.induction_on s (λ l H, nodup_pmap hf) H
id   └───────────────┘        └────────┘ └┘  
src  └───────────────┘           └────────┘
typ  └───────────────┘        └────────┘ └┘  
2303  
2304  instance nodup_decidable [decidable_eq α] (s : multiset α) : decidable (nodup s) :=
id                             └──────────┘        └──────┘     └───────┘  └───┘ 
src                            └──────────┘         └──────┘      └───────┘  └───┘
typ                            └──────────┘        └──────┘     └───────┘  └───┘ 
doc                                                 └──────┘                 └───┘
2305  quotient.rec_on_subsingleton s $ λ l, l.nodup_decidable
id   └──────────────────────────┘        └──────────────┘
src  └──────────────────────────┘           └──────────────┘
typ  └──────────────────────────┘        └──────────────┘
2306  
2307  theorem nodup_erase_eq_filter [decidable_eq α] (a : α) {s} : nodup s → s.erase a = filter (≠ a) s :=
id                                  └──────────┘                └───┘    └────┘   └────┘     
src                                 └──────────┘                  └───┘      └────┘    └────┘ 
typ                                 └──────────┘                └───┘    └────┘   └────┘     
doc                                                               └───┘      └────┘     └────┘
2308  quot.induction_on s $ λ l d, congr_arg coe $ nodup_erase_eq_filter a d
id   └───────────────┘         └───────┘ └─┘   └───────────────────┘  
src  └───────────────┘            └───────┘ └─┘   └───────────────────┘
typ  └───────────────┘         └───────┘ └─┘   └───────────────────┘  
2309  
2310  theorem nodup_erase_of_nodup [decidable_eq α] (a : α) {l} : nodup l → nodup (l.erase a) :=
id                                 └──────────┘                └───┘    └───┘  └────┘ 
src                                └──────────┘                  └───┘     └───┘   └────┘
typ                                └──────────┘                └───┘    └───┘  └────┘ 
doc                                                              └───┘     └───┘   └────┘
2311  nodup_of_le (erase_le _ _)
id   └─────────┘  └──────┘
src  └─────────┘  └──────┘
typ  └─────────┘  └──────┘
2312  
2313  theorem mem_erase_iff_of_nodup [decidable_eq α] {a b : α} {l} (d : nodup l) :
id                                   └──────────┘                     └───┘ 
src                                  └──────────┘                       └───┘
typ                                  └──────────┘                     └───┘ 
doc                                                                     └───┘
2314    a ∈ l.erase b ↔ a ≠ b ∧ a ∈ l :=
id       └────┘         
src        └────┘            
typ      └────┘         
doc         └────┘
2315  by rw nodup_erase_eq_filter b d; simp [and_comm]
id         └───────────────────┘          └──────┘
src     └─┘└───────────────────┘    └────┘└──────┘└─
typ     └─┘└───────────────────┘  └────┘└──────┘└─
doc     └─┘                         └────┘        └─
txt     └─┘                         └────┘        └─
par     └─┘                         └────┘        └─
pid                                            
st     └──────────────────────────────────────────────
2316  
src  
typ  
doc  
txt  
par  
pid  
st   
2317  theorem mem_erase_of_nodup [decidable_eq α] {a : α} {l} (h : nodup l) : a ∉ l.erase a :=
id                               └──────────┘                   └───┘       └────┘ 
src                              └──────────┘                     └───┘          └────┘
typ                              └──────────┘                   └───┘       └────┘ 
doc                                                               └───┘           └────┘
2318  by rw mem_erase_iff_of_nodup h; simp
id         └────────────────────┘ 
src     └─┘└────────────────────┘   └────
typ     └─┘└────────────────────┘  └────
doc     └─┘                         └────
txt     └─┘                         └────
par     └─┘                         └────
pid                                    
st     └──────────────────────────────────
2319  
src  
typ  
doc  
txt  
par  
pid  
st   
2320  theorem nodup_product {s : multiset α} {t : multiset β} : nodup s → nodup t → nodup (product s t) :=
id                              └──────┘        └──────┘     └───┘    └───┘    └───┘  └─────┘  
src                             └──────┘         └──────┘      └───┘     └───┘     └───┘  └─────┘
typ                             └──────┘        └──────┘     └───┘    └───┘    └───┘  └─────┘  
doc                             └──────┘         └──────┘      └───┘     └───┘     └───┘  └─────┘
2321  quotient.induction_on₂ s t $ λ l₁ l₂ d₁ d₂, by simp [nodup_product d₁ d₂]
id   └────────────────────┘       └┘ └┘ └┘ └┘           └───────────┘ └┘ └┘
src  └────────────────────┘                         └────┘└───────────┘    └─
typ  └────────────────────┘       └┘ └┘ └┘ └┘     └────┘└───────────┘└┘└┘└─
doc                                                 └────┘                 └─
txt                                                 └────┘                 └─
par                                                 └────┘                 └─
pid                                                                      
st                                                 └───────────────────────────
2322  
src  
typ  
doc  
txt  
par  
pid  
st   
2323  theorem nodup_sigma {σ : α → Type*} {s : multiset α} {t : Π a, multiset (σ a)} :
id                                           └──────┘            └──────┘   
src                                           └──────┘              └──────┘
typ                                          └──────┘            └──────┘   
doc                                           └──────┘              └──────┘
2324    nodup s → (∀ a, nodup (t a)) → nodup (s.sigma t) :=
id     └───┘         └───┘        └───┘  └────┘ 
src    └───┘           └───┘          └───┘   └────┘
typ    └───┘         └───┘        └───┘  └────┘ 
doc    └───┘           └───┘          └───┘   └────┘
2325  quot.induction_on s $ assume l₁,
id   └───────────────┘           └┘
src  └───────────────┘
typ  └───────────────┘           └┘
2326  begin
st   └─────
2327    choose f hf using assume a, quotient.exists_rep (t a),
id                                 └─────────────────┘  
src    └────────────────┘      └──┘└─────────────────┘   
typ    └────────────────┘      └──┘└─────────────────┘  
doc    └────────────────┘      └──┘                      
txt    └────────────────┘      └──┘                      
par    └────────────────┘      └──┘                      
pid          └┘└─┘└─────┘      └──┘                      
st   ──────────────────────────────────────────────────────┘└─
2328    rw show t = λ a, f a, from (eq.symm $ funext $ λ a, hf a),
id                              └─────┘   └────┘        └┘
src    └─┘      └──┘  └─────┘ └─────┘ └────┘  └──┘   
typ    └─┘     └──┘ └─────┘ └─────┘ └────┘  └──┘└┘ 
doc    └─┘       └──┘  └─────┘                 └──┘   
txt    └─┘       └──┘  └─────┘                 └──┘   
par    └─┘       └──┘  └─────┘                 └──┘   
pid             └──┘  └─────┘                 └──┘   
st   ──────────────────────────────────────────────────────────┘└─
2329    simpa using nodup_sigma
id                 └─────────┘
src    └──────────┘└─────────┘
typ    └──────────┘└─────────┘
doc    └──────────┘           
txt    └──────────┘           
par    └──────────┘           
pid         └────┘           
st   ─────────────────────────┘
2330  end
st   └─┘
2331  
2332  theorem nodup_filter_map (f : α → option β) {s : multiset α}
id                                    └────┘        └──────┘ 
src                                    └────┘         └──────┘
typ                                   └────┘        └──────┘ 
doc                                                   └──────┘
2333    (H : ∀ (a a' : α) (b : β), b ∈ f a → b ∈ f a' → a = a') :
id                                       └┘     └┘
src                                                    
typ                                      └┘     └┘
2334    nodup s → nodup (filter_map f s) :=
id     └───┘    └───┘  └────────┘  
src    └───┘     └───┘  └────────┘
typ    └───┘    └───┘  └────────┘  
doc    └───┘     └───┘  └────────┘
2335  quot.induction_on s $ λ l, nodup_filter_map H
id   └───────────────┘        └──────────────┘ 
src  └───────────────┘          └──────────────┘
typ  └───────────────┘        └──────────────┘ 
2336  
2337  theorem nodup_range (n : ℕ) : nodup (range n) := nodup_range _
id                                └───┘  └───┘      └─────────┘
src                               └───┘  └───┘       └─────────┘
typ                               └───┘  └───┘      └─────────┘
doc                                └───┘  └───┘
2338  
2339  theorem nodup_inter_left [decidable_eq α] {s : multiset α} (t) : nodup s → nodup (s ∩ t) :=
id                             └──────────┘        └──────┘         └───┘    └───┘    
src                            └──────────┘         └──────┘          └───┘     └───┘    
typ                            └──────────┘        └──────┘         └───┘    └───┘    
doc                                                 └──────┘          └───┘     └───┘
2340  nodup_of_le $ inter_le_left _ _
id   └─────────┘   └───────────┘
src  └─────────┘   └───────────┘
typ  └─────────┘   └───────────┘
2341  
2342  theorem nodup_inter_right [decidable_eq α] (s) {t : multiset α} : nodup t → nodup (s ∩ t) :=
id                              └──────────┘            └──────┘     └───┘    └───┘    
src                             └──────────┘             └──────┘      └───┘     └───┘    
typ                             └──────────┘            └──────┘     └───┘    └───┘    
doc                                                      └──────┘      └───┘     └───┘
2343  nodup_of_le $ inter_le_right _ _
id   └─────────┘   └────────────┘
src  └─────────┘   └────────────┘
typ  └─────────┘   └────────────┘
2344  
2345  @[simp] theorem nodup_union [decidable_eq α] {s t : multiset α} : nodup (s ∪ t) ↔ nodup s ∧ nodup t :=
id                                └──────────┘          └──────┘     └───┘       └───┘   └───┘ 
src                               └──────────┘           └──────┘      └───┘         └───┘    └───┘
typ                               └──────────┘          └──────┘     └───┘       └───┘   └───┘ 
doc    └──┘                                              └──────┘      └───┘           └───┘     └───┘
2346  ⟨λ h, ⟨nodup_of_le (le_union_left _ _) h, nodup_of_le (le_union_right _ _) h⟩,
id         └─────────┘  └───────────┘        └─────────┘  └────────────┘      
src         └─────────┘  └───────────┘         └─────────┘  └────────────┘
typ        └─────────┘  └───────────┘        └─────────┘  └────────────┘      
2347   λ ⟨h₁, h₂⟩, nodup_iff_count_le_one.2 $ λ a, by rw [count_union]; exact
id               └────────────────────┘               └─────────┘
src               └────────────────────┘            └──┘└─────────┘  └─────
typ              └────────────────────┘           └──┘└─────────┘  └─────
doc                                                  └──┘             └─────
txt                                                  └──┘             └─────
par                                                  └──┘             └─────
pid                                                    └┘                  
st                                                  └──────────────┘└───────
2348     max_le (nodup_iff_count_le_one.1 h₁ a) (nodup_iff_count_le_one.1 h₂ a)⟩
id      └────┘                           └┘     └────────────────────┘   └┘ 
src  ──┘└────┘                       └─┘   └┘ └────────────────────┘└─┘   
typ  ──┘└────┘                       └─┘└┘ └┘ └────────────────────┘└─┘└┘
doc  ──┘                             └─┘   └┘                       └─┘   
txt  ──┘                             └─┘   └┘                       └─┘   
par  ──┘                             └─┘   └┘                       └─┘   
pid  ──┘                             └─┘   └┘                       └─┘   
st   ────────────────────────────────────────────────────────────────────────┘
2349  
2350  @[simp] theorem nodup_powerset {s : multiset α} : nodup (powerset s) ↔ nodup s :=
id                                       └──────┘     └───┘  └──────┘    └───┘ 
src                                      └──────┘      └───┘  └──────┘     └───┘
typ                                      └──────┘     └───┘  └──────┘    └───┘ 
doc    └──┘                              └──────┘      └───┘                └───┘
2351  ⟨λ h, nodup_of_nodup_map _ (nodup_of_le (map_single_le_powerset _) h),
id        └────────────────┘    └─────────┘  └────────────────────┘    
src        └────────────────┘    └─────────┘  └────────────────────┘
typ       └────────────────┘    └─────────┘  └────────────────────┘    
2352    quotient.induction_on s $ λ l h,
id     └───────────────────┘       
src    └───────────────────┘
typ    └───────────────────┘       
2353    by simp; refine list.nodup_map_on _ (nodup_sublists'.2 h); exact
id                     └───────────────┘    └─────────────┘   
src       └──┘  └─────┘└───────────────┘└─┘ └─────────────┘└─┘   └─────
typ       └──┘  └─────┘└───────────────┘└─┘ └─────────────┘└─┘  └─────
doc       └──┘  └─────┘                 └─┘                └─┘   └─────
txt       └──┘  └─────┘                 └─┘                └─┘   └─────
par       └──┘  └─────┘                 └─┘                └─┘   └─────
pid                                    └─┘                └─┘        
st       └──────────────────────────────────────────────────────────────
2354    λ x sx y sy e,
src  ─┘ └─────────────
typ  ─┘ └─────────────
doc  ─┘ └─────────────
txt  ─┘ └─────────────
par  ─┘ └─────────────
pid  ─┘ └─────────────
st   ─────────────────
2355      (perm_ext_sublist_nodup h (mem_sublists'.1 sx) (mem_sublists'.1 sy)).1
id        └────────────────────┘                        └───────────┘
src  ───┘ └────────────────────┘               └─┘  └┘ └───────────┘└─┘  └────
typ  ───┘ └────────────────────┘              └─┘  └┘ └───────────┘└─┘  └────
doc  ───┘                                      └─┘  └┘              └─┘  └────
txt  ───┘                                      └─┘  └┘              └─┘  └────
par  ───┘                                      └─┘  └┘              └─┘  └────
pid  ───┘                                      └─┘  └┘              └─┘  └────
st   ───────────────────────────────────────────────────────────────────────────
2356        (quotient.exact e)⟩
id          └────────────┘
src  ─────┘ └────────────┘ 
typ  ─────┘ └────────────┘ 
doc  ─────┘                
txt  ─────┘                
par  ─────┘                
pid  ─────┘                
st   ───────────────────────┘
2357  
2358  theorem nodup_powerset_len {n : ℕ} {s : multiset α}
id                                          └──────┘ 
src                                         └──────┘
typ                                         └──────┘ 
doc                                          └──────┘
2359    (h : nodup s) : nodup (powerset_len n s) :=
id          └───┘     └───┘  └──────────┘  
src         └───┘      └───┘  └──────────┘
typ         └───┘     └───┘  └──────────┘  
doc         └───┘      └───┘
2360  nodup_of_le (powerset_len_le_powerset _ _) (nodup_powerset.2 h)
id   └─────────┘  └──────────────────────┘       └────────────┘  
src  └─────────┘  └──────────────────────┘       └────────────┘
typ  └─────────┘  └──────────────────────┘       └────────────┘  
2361  
2362  @[simp] lemma nodup_bind {s : multiset α} {t : α → multiset β} :
id                                 └──────┘           └──────┘ 
src                                └──────┘             └──────┘
typ                                └──────┘           └──────┘ 
doc    └──┘                        └──────┘             └──────┘
2363    nodup (bind s t) ↔ ((∀a∈s, nodup (t a)) ∧ (s.pairwise (λa b, disjoint (t a) (t b)))) :=
id     └───┘  └──┘           └───┘        └───────┘      └──────┘       
src    └───┘  └──┘               └───┘           └───────┘        └──────┘
typ    └───┘  └──┘           └───┘        └───────┘      └──────┘       
doc    └───┘  └──┘                └───┘            └───────┘        └──────┘
2364  have h₁ : ∀a, ∃l:list β, t a = l, from
id                  └──┘     
src                  └──┘       
typ                 └──┘     
2365    assume a, quot.induction_on (t a) $ assume l, ⟨l, rfl⟩,
id              └───────────────┘                   └─┘
src              └───────────────┘                       └─┘
typ             └───────────────┘                   └─┘
2366  let ⟨t', h'⟩ := classical.axiom_of_choice h₁ in
id   └─┘  └┘  └┘     └───────────────────────┘ └┘
src                  └───────────────────────┘
typ  └─┘  └┘  └┘     └───────────────────────┘ └┘
2367  have t = λa, t' a, from funext h',
id                       └────┘
src                         └────┘
typ                      └────┘
2368  have hd : symmetric (λa b, list.disjoint (t' a) (t' b)), from assume a b h, h.symm,
id             └───────┘      └───────────┘                               └───┘
src            └───────┘        └───────────┘                                     └───┘
typ            └───────┘      └───────────┘                               └───┘
doc                             └───────────┘
2369  quot.induction_on s $ by simp [this, list.nodup_bind, pairwise_coe_iff_pairwise hd]
id   └───────────────┘             └──┘  └─────────────┘  └───────────────────────┘ └┘
src  └───────────────┘        └────┘    └┘└─────────────┘└┘└───────────────────────┘  └─
typ  └───────────────┘       └────┘└──┘└┘└─────────────┘└┘└───────────────────────┘└┘└─
doc                           └────┘    └┘               └┘                           └─
txt                           └────┘    └┘               └┘                           └─
par                           └────┘    └┘               └┘                           └─
pid                                   └┘               └┘                           
st                           └───────────────────────────────────────────────────────────
2370  
src  
typ  
doc  
txt  
par  
pid  
st   
2371  theorem nodup_ext {s t : multiset α} : nodup s → nodup t → (s = t ↔ ∀ a, a ∈ s ↔ a ∈ t) :=
id                            └──────┘     └───┘    └───┘                   
src                           └──────┘      └───┘     └───┘                         
typ                           └──────┘     └───┘    └───┘                   
doc                           └──────┘      └───┘     └───┘
2372  quotient.induction_on₂ s t $ λ l₁ l₂ d₁ d₂, quotient.eq.trans $ perm_ext d₁ d₂
id   └────────────────────┘       └┘ └┘ └┘ └┘  └─────────┘└────┘   └──────┘ └┘ └┘
src  └────────────────────┘                      └─────────┘└────┘   └──────┘
typ  └────────────────────┘       └┘ └┘ └┘ └┘  └─────────┘└────┘   └──────┘ └┘ └┘
2373  
2374  theorem le_iff_subset {s t : multiset α} : nodup s → (s ≤ t ↔ s ⊆ t) :=
id                                └──────┘     └───┘           
src                               └──────┘      └───┘              
typ                               └──────┘     └───┘           
doc                               └──────┘      └───┘
2375  quotient.induction_on₂ s t $ λ l₁ l₂ d, ⟨subset_of_le, subperm_of_subset_nodup d⟩
id   └────────────────────┘       └┘ └┘    └──────────┘  └─────────────────────┘ 
src  └────────────────────┘                   └──────────┘  └─────────────────────┘
typ  └────────────────────┘       └┘ └┘    └──────────┘  └─────────────────────┘ 
2376  
2377  theorem range_le {m n : ℕ} : range m ≤ range n ↔ m ≤ n :=
id                               └───┘   └───┘     
src                              └───┘    └───┘      
typ                              └───┘   └───┘     
doc                               └───┘     └───┘
2378  (le_iff_subset (nodup_range _)).trans range_subset
id    └───────────┘  └─────────┘    └───┘  └──────────┘
src   └───────────┘  └─────────┘    └───┘  └──────────┘
typ   └───────────┘  └─────────┘    └───┘  └──────────┘
2379  
2380  theorem mem_sub_of_nodup [decidable_eq α] {a : α} {s t : multiset α} (d : nodup s) :
id                             └──────────┘                 └──────┘        └───┘ 
src                            └──────────┘                   └──────┘         └───┘
typ                            └──────────┘                 └──────┘        └───┘ 
doc                                                           └──────┘         └───┘
2381    a ∈ s - t ↔ a ∈ s ∧ a ∉ t :=
id                 
src                     
typ                
2382  ⟨λ h, ⟨mem_of_le (sub_le_self _ _) h, λ h',
id         └───────┘  └─────────┘          └┘
src         └───────┘  └─────────┘
typ        └───────┘  └─────────┘          └┘
2383    by refine count_eq_zero.1 _ h; rw [count_sub a s t, nat.sub_eq_zero_iff_le];
id               └───────────┘           └───────┘     └────────────────────┘
src       └─────┘└───────────┘└───┘   └──┘└───────┘   └┘└────────────────────┘
typ       └─────┘└───────────┘└───┘  └──┘└───────┘└┘└────────────────────┘
doc       └─────┘             └───┘   └──┘            └┘                      
txt       └─────┘             └───┘   └──┘            └┘                      
par       └─────┘             └───┘   └──┘            └┘                      
pid                          └───┘     └┘            └┘                      
st       └───────────────────────────────┘└─────────────┘└──────────────────────┘└─
2384       exact le_trans (nodup_iff_count_le_one.1 d _) (count_pos.2 h')⟩,
id              └──────┘  └────────────────────┘        └───────┘   └┘
src       └────┘└──────┘ └────────────────────┘└─┘ └──┘ └───────┘└─┘  
typ       └────┘└──────┘ └────────────────────┘└─┘└──┘ └───────┘└─┘└┘
doc       └────┘                               └─┘ └──┘          └─┘  
txt       └────┘                               └─┘ └──┘          └─┘  
par       └────┘                               └─┘ └──┘          └─┘  
pid                                           └─┘ └──┘          └─┘  
st   ──────────────────────────────────────────────────────────────────┘
2385   λ ⟨h₁, h₂⟩, or.resolve_right (mem_add.1 $ mem_of_le (le_sub_add _ _) h₁) h₂⟩
id      └┘  └┘   └──────────────┘  └─────┘    └───────┘  └────────┘
src               └──────────────┘  └─────┘    └───────┘  └────────┘
typ     └┘  └┘   └──────────────┘  └─────┘    └───────┘  └────────┘
2386  
2387  lemma map_eq_map_of_bij_of_nodup (f : α → γ) (g : β → γ) {s : multiset α} {t : multiset β}
id                                                             └──────┘        └──────┘ 
src                                                                └──────┘         └──────┘
typ                                                            └──────┘        └──────┘ 
doc                                                                └──────┘         └──────┘
2388    (hs : s.nodup) (ht : t.nodup) (i : Πa∈s, β)
id           └────┘        └────┘           
src           └────┘         └────┘
typ          └────┘        └────┘           
doc           └────┘         └────┘
2389    (hi : ∀a ha, i a ha ∈ t) (h : ∀a ha, f a = g (i a ha))
id             └┘    └┘           └┘         └┘
src                                            
typ            └┘    └┘           └┘         └┘
2390    (i_inj : ∀a₁ a₂ ha₁ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂)
id               └┘ └┘ └─┘ └─┘   └┘ └─┘   └┘ └─┘   └┘  └┘
src                                                     
typ              └┘ └┘ └─┘ └─┘   └┘ └─┘   └┘ └─┘   └┘  └┘
2391    (i_surj : ∀b∈t, ∃a ha, b = i a ha) :
id                    └┘     └┘
src                           
typ                   └┘     └┘
2392    s.map f = t.map g :=
id     └──┘   └──┘ 
src     └──┘     └──┘
typ    └──┘   └──┘ 
doc     └──┘      └──┘
2393  have t = s.attach.map (λ x, i x.1 x.2),
id          └─────┘└──┘         
src           └─────┘└──┘             
typ         └─────┘└──┘         
doc            └─────┘└──┘
2394    from (nodup_ext ht (nodup_map
id           └───────┘ └┘  └───────┘
src          └───────┘     └───────┘
typ          └───────┘ └┘  └───────┘
2395        (show function.injective (λ x : {x // x ∈ s}, i x.1 x.2), from λ x y hxy,
id               └────────────────┘                                 └─┘
src              └────────────────┘                          
typ              └────────────────┘                                 └─┘
2396          subtype.eq (i_inj x.1 y.1 x.2 y.2 hxy))
id           └────────┘  └───┘         └─┘
src          └────────┘                  
typ          └────────┘  └───┘         └─┘
2397        (nodup_attach.2 hs))).2
id          └──────────┘  └┘   
src         └──────────┘       
typ         └──────────┘  └┘   
2398      (λ x, by simp only [mem_map, true_and, subtype.exists, eq_comm, mem_attach];
id                          └─────┘  └──────┘  └────────────┘  └─────┘  └────────┘
src               └─────────┘└─────┘└┘└──────┘└┘└────────────┘└┘└─────┘└┘└────────┘
typ              └─────────┘└─────┘└┘└──────┘└┘└────────────┘└┘└─────┘└┘└────────┘
doc               └─────────┘       └┘        └┘              └┘       └┘          
txt               └─────────┘       └┘        └┘              └┘       └┘          
par               └─────────┘       └┘        └┘              └┘       └┘          
pid                   └──┘└┘       └┘        └┘              └┘       └┘          
st               └────────────────────────────────────────────────────────────────────
2399        exact ⟨i_surj _, λ ⟨y, hy⟩, hy.snd.symm ▸ hi _ _⟩),
id                └────┘          └┘     └──┘└───┘  └┘
src        └────┘       └──┘ └┘ └┘  └─┘  └──┘└───┘  └───┘
typ        └────┘ └────┘└──┘ └┘ └┘└┘└─┘  └──┘└───┘└┘└───┘
doc        └────┘       └──┘ └┘ └┘  └─┘              └───┘
txt        └────┘       └──┘ └┘ └┘  └─┘              └───┘
par        └────┘       └──┘ └┘ └┘  └─┘              └───┘
pid                    └──┘ └┘ └┘  └─┘              └───┘
st   ──────────────────────────────────────────────────────┘
2400  calc s.map f = s.pmap  (λ x _, f x) (λ _, id) : by rw [pmap_eq_map]
id        └──┘    └───┘                └┘           └─────────┘
src        └──┘      └───┘                     └┘       └──┘└─────────┘└┘
typ       └──┘    └───┘                └┘       └──┘└─────────┘└┘
doc        └──┘      └───┘                              └──┘           └┘
txt                                                     └──┘           └┘
par                                                     └──┘           └┘
pid                                                       └┘           
st                                                     └──────────────┘
2401  ... = s.attach.map (λ x, f x.1) : by rw [pmap_eq_map_attach]
id         └─────┘└──┘                   └────────────────┘
src         └─────┘└──┘                  └──┘└────────────────┘└┘
typ        └─────┘└──┘               └──┘└────────────────┘└┘
doc         └─────┘└──┘                   └──┘                  └┘
txt                                       └──┘                  └┘
par                                       └──┘                  └┘
pid                                         └┘                  
st                                       └─────────────────────┘
2402  ... = t.map g : by rw [this, multiset.map_map]; exact map_congr (λ x _, h _ _)
id         └──┘           └──┘  └──────────────┘         └───────┘         
src         └──┘        └──┘    └┘└──────────────┘  └────┘└───────┘  └────┘ └─────
typ        └──┘       └──┘└──┘└┘└──────────────┘  └────┘└───────┘  └────┘└─────
doc         └──┘        └──┘    └┘                  └────┘           └────┘ └─────
txt                     └──┘    └┘                  └────┘           └────┘ └─────
par                     └──┘    └┘                  └────┘           └────┘ └─────
pid                       └┘    └┘                                  └────┘ └───┘
st                     └───────┘└────────────────┘└────────────────────────────────
2403  
src  
typ  
doc  
txt  
par  
pid  
st   
2404  section
2405  variable [decidable_eq α]
id             └──────────┘
src            └──────────┘
typ            └──────────┘
2406  
2407  /- erase_dup -/
2408  
2409  /-- `erase_dup s` removes duplicates from `s`, yielding a `nodup` multiset. -/
2410  def erase_dup (s : multiset α) : multiset α :=
id                      └──────┘     └──────┘ 
src                     └──────┘      └──────┘
typ                     └──────┘     └──────┘ 
doc                     └──────┘      └──────┘
2411  quot.lift_on s (λ l, (l.erase_dup : multiset α))
id   └──────────┘        └────────┘   └──────┘ 
src  └──────────┘           └────────┘   └──────┘
typ  └──────────┘        └────────┘   └──────┘ 
doc                         └────────┘   └──────┘
2412    (λ s t p, quot.sound (perm_erase_dup_of_perm p))
id            └────────┘  └────────────────────┘ 
src              └────────┘  └────────────────────┘
typ           └────────┘  └────────────────────┘ 
2413  
2414  @[simp] theorem coe_erase_dup (l : list α) : @erase_dup α _ l = l.erase_dup := rfl
id                                      └──┘      └───────┘      └────────┘    └─┘
src                                     └──┘       └───────┘         └────────┘    └─┘
typ                                     └──┘      └───────┘      └────────┘    └─┘
doc    └──┘                                        └───────┘          └────────┘
2415  
2416  @[simp] theorem erase_dup_zero : @erase_dup α _ 0 = 0 := rfl
id                                     └───────┘            └─┘
src                                    └───────┘             └─┘
typ                                    └───────┘            └─┘
doc    └──┘                            └───────┘
2417  
2418  @[simp] theorem mem_erase_dup {a : α} {s : multiset α} : a ∈ erase_dup s ↔ a ∈ s :=
id                                             └──────┘       └───────┘     
src                                             └──────┘         └───────┘      
typ                                            └──────┘       └───────┘     
doc    └──┘                                     └──────┘          └───────┘
2419  quot.induction_on s $ λ l, mem_erase_dup
id   └───────────────┘        └───────────┘
src  └───────────────┘          └───────────┘
typ  └───────────────┘        └───────────┘
2420  
2421  @[simp] theorem erase_dup_cons_of_mem {a : α} {s : multiset α} : a ∈ s →
id                                                     └──────┘       
src                                                     └──────┘        
typ                                                    └──────┘       
doc    └──┘                                             └──────┘
2422    erase_dup (a::s) = erase_dup s :=
id     └───────┘  └┘   └───────┘ 
src    └───────┘   └┘    └───────┘
typ    └───────┘  └┘   └───────┘ 
doc    └───────┘   └┘     └───────┘
2423  quot.induction_on s $ λ l m, @congr_arg _ _ _ _ coe $ erase_dup_cons_of_mem m
id   └───────────────┘          └───────┘         └─┘   └───────────────────┘ 
src  └───────────────┘             └───────┘         └─┘   └───────────────────┘
typ  └───────────────┘          └───────┘         └─┘   └───────────────────┘ 
2424  
2425  @[simp] theorem erase_dup_cons_of_not_mem {a : α} {s : multiset α} : a ∉ s →
id                                                         └──────┘       
src                                                         └──────┘        
typ                                                        └──────┘       
doc    └──┘                                                 └──────┘
2426    erase_dup (a::s) = a :: erase_dup s :=
id     └───────┘  └┘    └┘ └───────┘ 
src    └───────┘   └┘      └┘ └───────┘
typ    └───────┘  └┘    └┘ └───────┘ 
doc    └───────┘   └┘       └┘ └───────┘
2427  quot.induction_on s $ λ l m, congr_arg coe $ erase_dup_cons_of_not_mem m
id   └───────────────┘         └───────┘ └─┘   └───────────────────────┘ 
src  └───────────────┘            └───────┘ └─┘   └───────────────────────┘
typ  └───────────────┘         └───────┘ └─┘   └───────────────────────┘ 
2428  
2429  theorem erase_dup_le (s : multiset α) : erase_dup s ≤ s :=
id                             └──────┘     └───────┘   
src                            └──────┘      └───────┘   
typ                            └──────┘     └───────┘   
doc                            └──────┘      └───────┘
2430  quot.induction_on s $ λ l, subperm_of_sublist $ erase_dup_sublist _
id   └───────────────┘        └────────────────┘   └───────────────┘
src  └───────────────┘          └────────────────┘   └───────────────┘
typ  └───────────────┘        └────────────────┘   └───────────────┘
2431  
2432  theorem erase_dup_subset (s : multiset α) : erase_dup s ⊆ s :=
id                                 └──────┘     └───────┘   
src                                └──────┘      └───────┘   
typ                                └──────┘     └───────┘   
doc                                └──────┘      └───────┘
2433  subset_of_le $ erase_dup_le _
id   └──────────┘   └──────────┘
src  └──────────┘   └──────────┘
typ  └──────────┘   └──────────┘
2434  
2435  theorem subset_erase_dup (s : multiset α) : s ⊆ erase_dup s :=
id                                 └──────┘       └───────┘ 
src                                └──────┘         └───────┘
typ                                └──────┘       └───────┘ 
doc                                └──────┘          └───────┘
2436  λ a, mem_erase_dup.2
id       └───────────┘
src       └───────────┘
typ      └───────────┘
2437  
2438  @[simp] theorem erase_dup_subset' {s t : multiset α} : erase_dup s ⊆ t ↔ s ⊆ t :=
id                                            └──────┘     └───────┘       
src                                           └──────┘      └───────┘         
typ                                           └──────┘     └───────┘       
doc    └──┘                                   └──────┘      └───────┘
2439  ⟨subset.trans (subset_erase_dup _), subset.trans (erase_dup_subset _)⟩
id    └──────────┘  └──────────────┘     └──────────┘  └──────────────┘
src   └──────────┘  └──────────────┘     └──────────┘  └──────────────┘
typ   └──────────┘  └──────────────┘     └──────────┘  └──────────────┘
2440  
2441  @[simp] theorem subset_erase_dup' {s t : multiset α} : s ⊆ erase_dup t ↔ s ⊆ t :=
id                                            └──────┘       └───────┘     
src                                           └──────┘         └───────┘      
typ                                           └──────┘       └───────┘     
doc    └──┘                                   └──────┘          └───────┘
2442  ⟨λ h, subset.trans h (erase_dup_subset _), λ h, subset.trans h (subset_erase_dup _)⟩
id        └──────────┘   └──────────────┘         └──────────┘   └──────────────┘
src        └──────────┘    └──────────────┘          └──────────┘    └──────────────┘
typ       └──────────┘   └──────────────┘         └──────────┘   └──────────────┘
2443  
2444  @[simp] theorem nodup_erase_dup (s : multiset α) : nodup (erase_dup s) :=
id                                        └──────┘     └───┘  └───────┘ 
src                                       └──────┘      └───┘  └───────┘
typ                                       └──────┘     └───┘  └───────┘ 
doc    └──┘                               └──────┘      └───┘  └───────┘
2445  quot.induction_on s nodup_erase_dup
id   └───────────────┘  └─────────────┘
src  └───────────────┘   └─────────────┘
typ  └───────────────┘  └─────────────┘
2446  
2447  theorem erase_dup_eq_self {s : multiset α} : erase_dup s = s ↔ nodup s :=
id                                  └──────┘     └───────┘     └───┘ 
src                                 └──────┘      └───────┘       └───┘
typ                                 └──────┘     └───────┘     └───┘ 
doc                                 └──────┘      └───────┘         └───┘
2448  ⟨λ e, e ▸ nodup_erase_dup s,
id          └─────────────┘ 
src           └─────────────┘
typ         └─────────────┘ 
2449   quot.induction_on s $ λ l h, congr_arg coe $ erase_dup_eq_self.2 h⟩
id    └───────────────┘         └───────┘ └─┘   └───────────────┘  
src   └───────────────┘            └───────┘ └─┘   └───────────────┘
typ   └───────────────┘         └───────┘ └─┘   └───────────────┘  
2450  
2451  theorem erase_dup_eq_zero {s : multiset α} : erase_dup s = 0 ↔ s = 0 :=
id                                  └──────┘     └───────┘       
src                                 └──────┘      └───────┘         
typ                                 └──────┘     └───────┘       
doc                                 └──────┘      └───────┘
2452  ⟨λ h, eq_zero_of_subset_zero $ h ▸ subset_erase_dup _,
id        └────────────────────┘     └──────────────┘
src        └────────────────────┘      └──────────────┘
typ       └────────────────────┘     └──────────────┘
2453   λ h, h.symm ▸ erase_dup_zero⟩
id        └───┘  └────────────┘
src         └───┘  └────────────┘
typ       └───┘  └────────────┘
2454  
2455  @[simp] theorem erase_dup_singleton {a : α} : erase_dup (a :: 0) = a :: 0 :=
id                                                └───────┘   └┘      └┘
src                                                └───────┘    └┘       └┘
typ                                               └───────┘   └┘      └┘
doc    └──┘                                        └───────┘    └┘        └┘
2456  erase_dup_eq_self.2 $ nodup_singleton _
id   └───────────────┘    └─────────────┘
src  └───────────────┘    └─────────────┘
typ  └───────────────┘    └─────────────┘
2457  
2458  theorem le_erase_dup {s t : multiset α} : s ≤ erase_dup t ↔ s ≤ t ∧ nodup s :=
id                               └──────┘       └───────┘       └───┘ 
src                              └──────┘         └───────┘          └───┘
typ                              └──────┘       └───────┘       └───┘ 
doc                              └──────┘          └───────┘             └───┘
2459  ⟨λ h, ⟨le_trans h (erase_dup_le _), nodup_of_le h (nodup_erase_dup _)⟩,
id         └──────┘   └──────────┘     └─────────┘   └─────────────┘
src         └──────┘    └──────────┘     └─────────┘    └─────────────┘
typ        └──────┘   └──────────┘     └─────────┘   └─────────────┘
2460   λ ⟨l, d⟩, (le_iff_subset d).2 $ subset.trans (subset_of_le l) (subset_erase_dup _)⟩
id            └───────────┘       └──────────┘  └──────────┘     └──────────────┘
src              └───────────┘       └──────────┘  └──────────┘     └──────────────┘
typ           └───────────┘       └──────────┘  └──────────┘     └──────────────┘
2461  
2462  theorem erase_dup_ext {s t : multiset α} : erase_dup s = erase_dup t ↔ ∀ a, a ∈ s ↔ a ∈ t :=
id                                └──────┘     └───────┘   └───────┘             
src                               └──────┘      └───────┘    └───────┘                 
typ                               └──────┘     └───────┘   └───────┘             
doc                               └──────┘      └───────┘     └───────┘
2463  by simp [nodup_ext]
id            └───────┘
src     └────┘└───────┘└─
typ     └────┘└───────┘└─
doc     └────┘         └─
txt     └────┘         └─
par     └────┘         └─
pid                  
st     └─────────────────
2464  
src  
typ  
doc  
txt  
par  
pid  
st   
2465  theorem erase_dup_map_erase_dup_eq [decidable_eq β] (f : α → β) (s : multiset α) :
id                                       └──────────┘                  └──────┘ 
src                                      └──────────┘                     └──────┘
typ                                      └──────────┘                  └──────┘ 
doc                                                                       └──────┘
2466    erase_dup (map f (erase_dup s)) = erase_dup (map f s) := by simp [erase_dup_ext]
id     └───────┘  └─┘   └───────┘     └───────┘  └─┘                └───────────┘
src    └───────┘  └─┘    └───────┘      └───────┘  └─┘            └────┘└───────────┘└─
typ    └───────┘  └─┘   └───────┘     └───────┘  └─┘          └────┘└───────────┘└─
doc    └───────┘  └─┘    └───────┘       └───────┘  └─┘            └────┘             └─
txt                                                                └────┘             └─
par                                                                └────┘             └─
pid                                                                                 
st                                                                └─────────────────────
2467  
src  
typ  
doc  
txt  
par  
pid  
st   
2468  /- finset insert -/
src  ────────────────────
typ  ────────────────────
doc  ────────────────────
txt  ────────────────────
par  ────────────────────
pid  ────────────────────
st   ────────────────────
2469  
src  
typ  
doc  
txt  
par  
pid  
st   
2470  /-- `ndinsert a s` is the lift of the list `insert` operation. This operation
2471    does not respect multiplicities, unlike `cons`, but it is suitable as
2472    an insert operation on `finset`. -/
2473  def ndinsert (a : α) (s : multiset α) : multiset α :=
id                            └──────┘     └──────┘ 
src                            └──────┘      └──────┘
typ                           └──────┘     └──────┘ 
doc                            └──────┘      └──────┘
2474  quot.lift_on s (λ l, (l.insert a : multiset α))
id   └──────────┘        └─────┘    └──────┘ 
src  └──────────┘           └─────┘     └──────┘
typ  └──────────┘        └─────┘    └──────┘ 
doc                                     └──────┘
2475    (λ s t p, quot.sound (perm_insert a p))
id            └────────┘  └─────────┘  
src              └────────┘  └─────────┘
typ           └────────┘  └─────────┘  
2476  
2477  @[simp] theorem coe_ndinsert (a : α) (l : list α) : ndinsert a l = (insert a l : list α) := rfl
id                                            └──┘     └──────┘     └────┘     └──┘      └─┘
src                                            └──┘      └──────┘       └────┘       └──┘       └─┘
typ                                           └──┘     └──────┘     └────┘     └──┘      └─┘
doc    └──┘                                              └──────┘
2478  
2479  @[simp] theorem ndinsert_zero (a : α) : ndinsert a 0 = a::0 := rfl
id                                          └──────┘     └┘     └─┘
src                                          └──────┘       └┘     └─┘
typ                                         └──────┘     └┘     └─┘
doc    └──┘                                  └──────┘        └┘
2480  
2481  @[simp] theorem ndinsert_of_mem {a : α} {s : multiset α} : a ∈ s → ndinsert a s = s :=
id                                               └──────┘          └──────┘    
src                                               └──────┘             └──────┘     
typ                                              └──────┘          └──────┘    
doc    └──┘                                       └──────┘              └──────┘
2482  quot.induction_on s $ λ l h, congr_arg coe $ insert_of_mem h
id   └───────────────┘         └───────┘ └─┘   └───────────┘ 
src  └───────────────┘            └───────┘ └─┘   └───────────┘
typ  └───────────────┘         └───────┘ └─┘   └───────────┘ 
2483  
2484  @[simp] theorem ndinsert_of_not_mem {a : α} {s : multiset α} : a ∉ s → ndinsert a s = a :: s :=
id                                                   └──────┘          └──────┘     └┘ 
src                                                   └──────┘             └──────┘        └┘
typ                                                  └──────┘          └──────┘     └┘ 
doc    └──┘                                           └──────┘              └──────┘         └┘
2485  quot.induction_on s $ λ l h, congr_arg coe $ insert_of_not_mem h
id   └───────────────┘         └───────┘ └─┘   └───────────────┘ 
src  └───────────────┘            └───────┘ └─┘   └───────────────┘
typ  └───────────────┘         └───────┘ └─┘   └───────────────┘ 
2486  
2487  @[simp] theorem mem_ndinsert {a b : α} {s : multiset α} : a ∈ ndinsert b s ↔ a = b ∨ a ∈ s :=
id                                              └──────┘       └──────┘          
src                                              └──────┘         └──────┘              
typ                                             └──────┘       └──────┘          
doc    └──┘                                      └──────┘          └──────┘
2488  quot.induction_on s $ λ l, mem_insert_iff
id   └───────────────┘        └────────────┘
src  └───────────────┘          └────────────┘
typ  └───────────────┘        └────────────┘
2489  
2490  @[simp] theorem le_ndinsert_self (a : α) (s : multiset α) : s ≤ ndinsert a s :=
id                                                └──────┘       └──────┘  
src                                                └──────┘         └──────┘
typ                                               └──────┘       └──────┘  
doc    └──┘                                        └──────┘          └──────┘
2491  quot.induction_on s $ λ l, subperm_of_sublist $ sublist_of_suffix $ suffix_insert _ _
id   └───────────────┘        └────────────────┘   └───────────────┘   └───────────┘
src  └───────────────┘          └────────────────┘   └───────────────┘   └───────────┘
typ  └───────────────┘        └────────────────┘   └───────────────┘   └───────────┘
2492  
2493  @[simp] theorem mem_ndinsert_self (a : α) (s : multiset α) : a ∈ ndinsert a s :=
id                                                 └──────┘       └──────┘  
src                                                 └──────┘         └──────┘
typ                                                └──────┘       └──────┘  
doc    └──┘                                         └──────┘          └──────┘
2494  mem_ndinsert.2 (or.inl rfl)
id   └──────────┘   └────┘ └─┘
src  └──────────┘   └────┘ └─┘
typ  └──────────┘   └────┘ └─┘
2495  
2496  @[simp] theorem mem_ndinsert_of_mem {a b : α} {s : multiset α} (h : a ∈ s) : a ∈ ndinsert b s :=
id                                                     └──────┘                └──────┘  
src                                                     └──────┘                    └──────┘
typ                                                    └──────┘                └──────┘  
doc    └──┘                                             └──────┘                      └──────┘
2497  mem_ndinsert.2 (or.inr h)
id   └──────────┘   └────┘ 
src  └──────────┘   └────┘
typ  └──────────┘   └────┘ 
2498  
2499  @[simp] theorem length_ndinsert_of_mem {a : α} [decidable_eq α] {s : multiset α} (h : a ∈ s) :
id                                                  └──────────┘        └──────┘          
src                                                  └──────────┘         └──────┘           
typ                                                 └──────────┘        └──────┘          
doc    └──┘                                                               └──────┘
2500    card (ndinsert a s) = card s :=
id     └──┘  └──────┘     └──┘ 
src    └──┘  └──────┘       └──┘
typ    └──┘  └──────┘     └──┘ 
doc    └──┘  └──────┘        └──┘
2501  by simp [h]
id            
src     └────┘ └─
typ     └────┘└─
doc     └────┘ └─
txt     └────┘ └─
par     └────┘ └─
pid          
st     └─────────
2502  
src  
typ  
doc  
txt  
par  
pid  
st   
2503  @[simp] theorem length_ndinsert_of_not_mem {a : α} [decidable_eq α] {s : multiset α} (h : a ∉ s) :
id                                                      └──────────┘        └──────┘          
src                                                      └──────────┘         └──────┘           
typ                                                     └──────────┘        └──────┘          
doc    └──┘                                                                   └──────┘
2504    card (ndinsert a s) = card s + 1 :=
id     └──┘  └──────┘     └──┘  
src    └──┘  └──────┘       └──┘   
typ    └──┘  └──────┘     └──┘  
doc    └──┘  └──────┘        └──┘
2505  by simp [h]
id            
src     └────┘ └─
typ     └────┘└─
doc     └────┘ └─
txt     └────┘ └─
par     └────┘ └─
pid          
st     └─────────
2506  
src  
typ  
doc  
txt  
par  
pid  
st   
2507  theorem erase_dup_cons {a : α} {s : multiset α} :
id                                      └──────┘ 
src                                      └──────┘
typ                                     └──────┘ 
doc                                      └──────┘
2508    erase_dup (a::s) = ndinsert a (erase_dup s) :=
id     └───────┘  └┘   └──────┘   └───────┘ 
src    └───────┘   └┘    └──────┘    └───────┘
typ    └───────┘  └┘   └──────┘   └───────┘ 
doc    └───────┘   └┘     └──────┘    └───────┘
2509  by by_cases a ∈ s; simp [h]
id                         
src     └───────┘    └────┘ └─
typ     └───────┘  └────┘└─
doc     └───────┘     └────┘ └─
txt     └───────┘     └────┘ └─
par     └───────┘     └────┘ └─
pid                       
st     └─────────────────────────
2510  
src  
typ  
doc  
txt  
par  
pid  
st   
2511  theorem nodup_ndinsert (a : α) {s : multiset α} : nodup s → nodup (ndinsert a s) :=
id                                      └──────┘     └───┘    └───┘  └──────┘  
src                                      └──────┘      └───┘     └───┘  └──────┘
typ                                     └──────┘     └───┘    └───┘  └──────┘  
doc                                      └──────┘      └───┘     └───┘  └──────┘
2512  quot.induction_on s $ λ l, nodup_insert
id   └───────────────┘        └──────────┘
src  └───────────────┘          └──────────┘
typ  └───────────────┘        └──────────┘
2513  
2514  theorem ndinsert_le {a : α} {s t : multiset α} : ndinsert a s ≤ t ↔ s ≤ t ∧ a ∈ t :=
id                                     └──────┘     └──────┘            
src                                     └──────┘      └──────┘                 
typ                                    └──────┘     └──────┘            
doc                                     └──────┘      └──────┘
2515  ⟨λ h, ⟨le_trans (le_ndinsert_self _ _) h, mem_of_le h (mem_ndinsert_self _ _)⟩,
id         └──────┘  └──────────────┘        └───────┘   └───────────────┘
src         └──────┘  └──────────────┘         └───────┘    └───────────────┘
typ        └──────┘  └──────────────┘        └───────┘   └───────────────┘
2516   λ ⟨l, m⟩, if h : a ∈ s then by simp [h, l] else
id             └┘                        
src             └┘                  └────┘ └┘ └┘
typ            └┘                └────┘└┘└┘
doc                                  └────┘ └┘ └┘
txt                                  └────┘ └┘ └┘
par                                  └────┘ └┘ └┘
pid                                       └┘ 
st                                  └───────────┘
2517     by rw [ndinsert_of_not_mem h, ← cons_erase m, cons_le_cons_iff,
id             └─────────────────┘     └────────┘   └──────────────┘
src        └──┘└─────────────────┘ └──┘└────────┘ └┘└──────────────┘└─
typ        └──┘└─────────────────┘└──┘└────────┘└┘└──────────────┘└─
doc        └──┘                    └──┘           └┘                └─
txt        └──┘                    └──┘           └┘                └─
par        └──┘                    └──┘           └┘                └─
pid          └┘                    └──┘           └┘                └─
st        └────────────────────────┘└──────────────┘└────────────────┘└─
2518            ← le_cons_of_not_mem h, cons_erase m]; exact l⟩
id               └────────────────┘   └────────┘          
src  ───────────┘└────────────────┘ └┘└────────┘   └────┘
typ  ───────────┘└────────────────┘└┘└────────┘  └────┘
doc  ───────────┘                   └┘             └────┘
txt  ───────────┘                   └┘             └────┘
par  ───────────┘                   └┘             └────┘
pid  ───────────┘                   └┘                  
st   ───────────────────────────────┘└────────────┘└───────┘
2519  
2520  lemma attach_ndinsert (a : α) (s : multiset α) :
id                                     └──────┘ 
src                                     └──────┘
typ                                    └──────┘ 
doc                                     └──────┘
2521    (s.ndinsert a).attach =
id      └───────┘  └────┘  
src      └───────┘   └────┘  
typ     └───────┘  └────┘  
doc      └───────┘   └────┘
2522      ndinsert ⟨a, mem_ndinsert_self a s⟩ (s.attach.map $ λp, ⟨p.1, mem_ndinsert_of_mem p.2⟩) :=
id       └──────┘    └───────────────┘     └─────┘└──┘          └─────────────────┘ 
src      └──────┘     └───────────────┘        └─────┘└──┘            └─────────────────┘  
typ      └──────┘    └───────────────┘     └─────┘└──┘          └─────────────────┘ 
doc      └──────┘                              └─────┘└──┘
2523  have eq : ∀h : ∀(p : {x // x ∈ s}), p.1 ∈ s,
id                                    
src                                       
typ                                   
2524      (λ (p : {x // x ∈ s}), ⟨p.val, h p⟩ : {x // x ∈ s} → {x // x ∈ s}) = id, from
id                          └──┘                           └┘
src                             └──┘                                   └┘
typ                         └──┘                           └┘
2525    assume h, funext $ assume p, subtype.eq rfl,
id              └────┘            └────────┘ └─┘
src              └────┘             └────────┘ └─┘
typ             └────┘            └────────┘ └─┘
2526  have ∀t (eq : s.ndinsert a = t), t.attach = ndinsert ⟨a, eq ▸ mem_ndinsert_self a s⟩
id                └───────┘      └─────┘  └──────┘    └┘  └───────────────┘  
src                 └───────┘         └─────┘  └──────┘     └┘  └───────────────┘
typ               └───────┘      └─────┘  └──────┘    └┘  └───────────────┘  
doc                 └───────┘          └─────┘   └──────┘
2527    (s.attach.map $ λp, ⟨p.1, eq ▸ mem_ndinsert_of_mem p.2⟩),
id      └─────┘└──┘          └┘  └─────────────────┘ 
src      └─────┘└──┘            └┘  └─────────────────┘  
typ     └─────┘└──┘          └┘  └─────────────────┘ 
doc      └─────┘└──┘
2528  begin
st   └─────
2529    intros t ht,
src    └─────────┘
typ    └─────────┘
doc    └─────────┘
txt    └─────────┘
par    └─────────┘
pid          └───┘
st   ────────────┘└─
2530    by_cases a ∈ s,
id                
src    └───────┘ 
typ    └───────┘
doc    └───────┘  
txt    └───────┘  
par    └───────┘  
pid              
st   ───────────────┘└─
2531    { rw [ndinsert_of_mem h] at ht,
id           └─────────────┘ 
src      └──┘└─────────────┘ └─────┘
typ      └──┘└─────────────┘└─────┘
doc      └──┘                └─────┘
txt      └──┘                └─────┘
par      └──┘                └─────┘
pid        └┘                └────┘
st   ───┘└───────────────────┘└────┘└─
2532      subst ht,
id             └┘
src      └────┘
typ      └────┘└┘
doc      └────┘
txt      └────┘
par      └────┘
pid           
st   ───────────┘└─
2533      rw [eq, map_id, ndinsert_of_mem (mem_attach _ _)] },
id           └┘  └────┘  └─────────────┘  └────────┘
src      └──┘└┘└┘└────┘└┘└─────────────┘ └────────┘└─────┘
typ      └──┘└┘└┘└────┘└┘└─────────────┘ └────────┘└─────┘
doc      └──┘  └┘      └┘                          └─────┘
txt      └──┘  └┘      └┘                          └─────┘
par      └──┘  └┘      └┘                          └─────┘
pid        └┘  └┘      └┘                          └────┘
st   ─────────┘└──────┘└────────────────────────────────┘└┘
2534    { rw [ndinsert_of_not_mem h] at ht,
id           └─────────────────┘ 
src      └──┘└─────────────────┘ └─────┘
typ      └──┘└─────────────────┘└─────┘
doc      └──┘                    └─────┘
txt      └──┘                    └─────┘
par      └──┘                    └─────┘
pid        └┘                    └────┘
st   ────────────────────────────┘└────┘└─
2535      subst ht,
id             └┘
src      └────┘
typ      └────┘└┘
doc      └────┘
txt      └────┘
par      └────┘
pid           
st   ───────────┘└─
2536      simp [attach_cons, h] }
id             └─────────┘  
src      └────┘└─────────┘└┘ └┘
typ      └────┘└─────────┘└┘└┘
doc      └────┘           └┘ └┘
txt      └────┘           └┘ └┘
par      └────┘           └┘ └┘
pid                     └┘ 
st   ─────────────────────────┘└─
2537  end,
st   ──┘
2538  this _ rfl
id   └──┘   └─┘
src         └─┘
typ  └──┘   └─┘
2539  
2540  @[simp] theorem disjoint_ndinsert_left {a : α} {s t : multiset α} :
id                                                        └──────┘ 
src                                                        └──────┘
typ                                                       └──────┘ 
doc    └──┘                                                └──────┘
2541    disjoint (ndinsert a s) t ↔ a ∉ t ∧ disjoint s t :=
id     └──────┘  └──────┘          └──────┘  
src    └──────┘  └──────┘               └──────┘
typ    └──────┘  └──────┘          └──────┘  
doc    └──────┘  └──────┘                  └──────┘
2542  iff.trans (by simp [disjoint]) disjoint_cons_left
id   └───────┘           └──────┘   └────────────────┘
src  └───────┘     └────┘└──────┘  └────────────────┘
typ  └───────┘     └────┘└──────┘  └────────────────┘
doc                └────┘└──────┘
txt                └────┘        
par                └────┘        
pid                            
st                └──────────────┘
2543  
2544  @[simp] theorem disjoint_ndinsert_right {a : α} {s t : multiset α} :
id                                                         └──────┘ 
src                                                         └──────┘
typ                                                        └──────┘ 
doc    └──┘                                                 └──────┘
2545    disjoint s (ndinsert a t) ↔ a ∉ s ∧ disjoint s t :=
id     └──────┘   └──────┘         └──────┘  
src    └──────┘    └──────┘             └──────┘
typ    └──────┘   └──────┘         └──────┘  
doc    └──────┘    └──────┘                └──────┘
2546  disjoint_comm.trans $ by simp
id   └───────────┘└────┘
src  └───────────┘└────┘      └────
typ  └───────────┘└────┘      └────
doc                           └────
txt                           └────
par                           └────
pid                               
st                           └─────
2547  
src  
typ  
doc  
txt  
par  
pid  
st   
2548  /- finset union -/
src  ───────────────────
typ  ───────────────────
doc  ───────────────────
txt  ───────────────────
par  ───────────────────
pid  ───────────────────
st   ───────────────────
2549  
src  
typ  
doc  
txt  
par  
pid  
st   
2550  /-- `ndunion s t` is the lift of the list `union` operation. This operation
2551    does not respect multiplicities, unlike `s ∪ t`, but it is suitable as
2552    a union operation on `finset`. (`s ∪ t` would also work as a union operation
2553    on finset, but this is more efficient.) -/
2554  def ndunion (s t : multiset α) : multiset α :=
id                      └──────┘     └──────┘ 
src                     └──────┘      └──────┘
typ                     └──────┘     └──────┘ 
doc                     └──────┘      └──────┘
2555  quotient.lift_on₂ s t (λ l₁ l₂, (l₁.union l₂ : multiset α)) $ λ v₁ v₂ w₁ w₂ p₁ p₂,
id   └───────────────┘      └┘ └┘   └┘└────┘ └┘   └──────┘        └┘ └┘ └┘ └┘ └┘ └┘
src  └───────────────┘                  └────┘      └──────┘
typ  └───────────────┘      └┘ └┘   └┘└────┘ └┘   └──────┘        └┘ └┘ └┘ └┘ └┘ └┘
doc                                                 └──────┘
2556    quot.sound $ perm_union p₁ p₂
id     └────────┘   └────────┘ └┘ └┘
src    └────────┘   └────────┘
typ    └────────┘   └────────┘ └┘ └┘
2557  
2558  @[simp] theorem coe_ndunion (l₁ l₂ : list α) : @ndunion α _ l₁ l₂ = (l₁ ∪ l₂ : list α) := rfl
id                                        └──┘      └─────┘    └┘ └┘   └┘  └┘   └──┘      └─┘
src                                       └──┘       └─────┘                      └──┘       └─┘
typ                                       └──┘      └─────┘    └┘ └┘   └┘  └┘   └──┘      └─┘
doc    └──┘                                          └─────┘
2559  
2560  @[simp] theorem zero_ndunion (s : multiset α) : ndunion 0 s = s :=
id                                     └──────┘     └─────┘     
src                                    └──────┘      └─────┘     
typ                                    └──────┘     └─────┘     
doc    └──┘                            └──────┘      └─────┘
2561  quot.induction_on s $ λ l, rfl
id   └───────────────┘        └─┘
src  └───────────────┘          └─┘
typ  └───────────────┘        └─┘
2562  
2563  @[simp] theorem cons_ndunion (s t : multiset α) (a : α) : ndunion (a :: s) t = ndinsert a (ndunion s t) :=
id                                       └──────┘            └─────┘   └┘     └──────┘   └─────┘  
src                                      └──────┘              └─────┘    └┘       └──────┘    └─────┘
typ                                      └──────┘            └─────┘   └┘     └──────┘   └─────┘  
doc    └──┘                              └──────┘              └─────┘    └┘        └──────┘    └─────┘
2564  quotient.induction_on₂ s t $ λ l₁ l₂, rfl
id   └────────────────────┘       └┘ └┘  └─┘
src  └────────────────────┘                └─┘
typ  └────────────────────┘       └┘ └┘  └─┘
2565  
2566  @[simp] theorem mem_ndunion {s t : multiset α} {a : α} : a ∈ ndunion s t ↔ a ∈ s ∨ a ∈ t :=
id                                      └──────┘              └─────┘          
src                                     └──────┘                 └─────┘              
typ                                     └──────┘              └─────┘          
doc    └──┘                             └──────┘                  └─────┘
2567  quotient.induction_on₂ s t $ λ l₁ l₂, list.mem_union
id   └────────────────────┘       └┘ └┘  └────────────┘
src  └────────────────────┘                └────────────┘
typ  └────────────────────┘       └┘ └┘  └────────────┘
2568  
2569  theorem le_ndunion_right (s t : multiset α) : t ≤ ndunion s t :=
id                                   └──────┘       └─────┘  
src                                  └──────┘         └─────┘
typ                                  └──────┘       └─────┘  
doc                                  └──────┘          └─────┘
2570  quotient.induction_on₂ s t $ λ l₁ l₂,
id   └────────────────────┘       └┘ └┘
src  └────────────────────┘
typ  └────────────────────┘       └┘ └┘
2571  subperm_of_sublist $ sublist_of_suffix $ suffix_union_right _ _
id   └────────────────┘   └───────────────┘   └────────────────┘
src  └────────────────┘   └───────────────┘   └────────────────┘
typ  └────────────────┘   └───────────────┘   └────────────────┘
2572  
2573  theorem ndunion_le_add (s t : multiset α) : ndunion s t ≤ s + t :=
id                                 └──────┘     └─────┘      
src                                └──────┘      └─────┘        
typ                                └──────┘     └─────┘      
doc                                └──────┘      └─────┘
2574  quotient.induction_on₂ s t $ λ l₁ l₂, subperm_of_sublist $ union_sublist_append _ _
id   └────────────────────┘       └┘ └┘  └────────────────┘   └──────────────────┘
src  └────────────────────┘                └────────────────┘   └──────────────────┘
typ  └────────────────────┘       └┘ └┘  └────────────────┘   └──────────────────┘
2575  
2576  theorem ndunion_le {s t u : multiset α} : ndunion s t ≤ u ↔ s ⊆ u ∧ t ≤ u :=
id                               └──────┘     └─────┘            
src                              └──────┘      └─────┘                 
typ                              └──────┘     └─────┘            
doc                              └──────┘      └─────┘
2577  multiset.induction_on s (by simp) (by simp [ndinsert_le, and_comm, and.left_comm] {contextual := tt})
id   └───────────────────┘                      └─────────┘  └──────┘  └───────────┘                 └┘
src  └───────────────────┘       └──┘      └────┘└─────────┘└┘└──────┘└┘└───────────┘└┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └────┘└─────────┘└┘└──────┘└┘└───────────┘└┘ └────────────┘└┘
doc                              └──┘      └────┘           └┘        └┘             └┘ └────────────┘  
txt                              └──┘      └────┘           └┘        └┘             └┘ └────────────┘  
par                              └──┘      └────┘           └┘        └┘             └┘ └────────────┘  
pid                                                       └┘        └┘              └────────────┘  
st                              └───┘     └─────────────────────────────────────────────────────────────┘
2578  
2579  theorem subset_ndunion_left (s t : multiset α) : s ⊆ ndunion s t :=
id                                      └──────┘       └─────┘  
src                                     └──────┘         └─────┘
typ                                     └──────┘       └─────┘  
doc                                     └──────┘          └─────┘
2580  λ a h, mem_ndunion.2 $ or.inl h
id        └─────────┘    └────┘ 
src         └─────────┘    └────┘
typ       └─────────┘    └────┘ 
2581  
2582  theorem le_ndunion_left {s} (t : multiset α) (d : nodup s) : s ≤ ndunion s t :=
id                                    └──────┘        └───┘       └─────┘  
src                                   └──────┘         └───┘         └─────┘
typ                                   └──────┘        └───┘       └─────┘  
doc                                   └──────┘         └───┘          └─────┘
2583  (le_iff_subset d).2 $ subset_ndunion_left _ _
id    └───────────┘      └─────────────────┘
src   └───────────┘       └─────────────────┘
typ   └───────────┘      └─────────────────┘
2584  
2585  theorem ndunion_le_union (s t : multiset α) : ndunion s t ≤ s ∪ t :=
id                                   └──────┘     └─────┘      
src                                  └──────┘      └─────┘        
typ                                  └──────┘     └─────┘      
doc                                  └──────┘      └─────┘
2586  ndunion_le.2 ⟨subset_of_le (le_union_left _ _), le_union_right _ _⟩
id   └────────┘   └──────────┘  └───────────┘       └────────────┘
src  └────────┘   └──────────┘  └───────────┘       └────────────┘
typ  └────────┘   └──────────┘  └───────────┘       └────────────┘
2587  
2588  theorem nodup_ndunion (s : multiset α) {t : multiset α} : nodup t → nodup (ndunion s t) :=
id                              └──────┘        └──────┘     └───┘    └───┘  └─────┘  
src                             └──────┘         └──────┘      └───┘     └───┘  └─────┘
typ                             └──────┘        └──────┘     └───┘    └───┘  └─────┘  
doc                             └──────┘         └──────┘      └───┘     └───┘  └─────┘
2589  quotient.induction_on₂ s t $ λ l₁ l₂, list.nodup_union _
id   └────────────────────┘       └┘ └┘  └──────────────┘
src  └────────────────────┘                └──────────────┘
typ  └────────────────────┘       └┘ └┘  └──────────────┘
2590  
2591  @[simp] theorem ndunion_eq_union {s t : multiset α} (d : nodup s) : ndunion s t = s ∪ t :=
id                                           └──────┘        └───┘     └─────┘      
src                                          └──────┘         └───┘      └─────┘        
typ                                          └──────┘        └───┘     └─────┘      
doc    └──┘                                  └──────┘         └───┘      └─────┘
2592  le_antisymm (ndunion_le_union _ _) $ union_le (le_ndunion_left _ d) (le_ndunion_right _ _)
id   └─────────┘  └──────────────┘        └──────┘  └─────────────┘      └──────────────┘
src  └─────────┘  └──────────────┘        └──────┘  └─────────────┘       └──────────────┘
typ  └─────────┘  └──────────────┘        └──────┘  └─────────────┘      └──────────────┘
2593  
2594  theorem erase_dup_add (s t : multiset α) : erase_dup (s + t) = ndunion s (erase_dup t) :=
id                                └──────┘     └───────┘       └─────┘   └───────┘ 
src                               └──────┘      └───────┘         └─────┘    └───────┘
typ                               └──────┘     └───────┘       └─────┘   └───────┘ 
doc                               └──────┘      └───────┘           └─────┘    └───────┘
2595  quotient.induction_on₂ s t $ λ l₁ l₂, congr_arg coe $ erase_dup_append _ _
id   └────────────────────┘       └┘ └┘  └───────┘ └─┘   └──────────────┘
src  └────────────────────┘                └───────┘ └─┘   └──────────────┘
typ  └────────────────────┘       └┘ └┘  └───────┘ └─┘   └──────────────┘
2596  
2597  /- finset inter -/
2598  
2599  /-- `ndinter s t` is the lift of the list `∩` operation. This operation
2600    does not respect multiplicities, unlike `s ∩ t`, but it is suitable as
2601    an intersection operation on `finset`. (`s ∩ t` would also work as a union operation
2602    on finset, but this is more efficient.) -/
2603  def ndinter (s t : multiset α) : multiset α := filter (∈ t) s
id                      └──────┘     └──────┘     └────┘     
src                     └──────┘      └──────┘      └────┘ 
typ                     └──────┘     └──────┘     └────┘     
doc                     └──────┘      └──────┘      └────┘
2604  
2605  @[simp] theorem coe_ndinter (l₁ l₂ : list α) : @ndinter α _ l₁ l₂ = (l₁ ∩ l₂ : list α) := rfl
id                                        └──┘      └─────┘    └┘ └┘   └┘  └┘   └──┘      └─┘
src                                       └──┘       └─────┘                      └──┘       └─┘
typ                                       └──┘      └─────┘    └┘ └┘   └┘  └┘   └──┘      └─┘
doc    └──┘                                          └─────┘
2606  
2607  @[simp] theorem zero_ndinter (s : multiset α) : ndinter 0 s = 0 := rfl
id                                     └──────┘     └─────┘          └─┘
src                                    └──────┘      └─────┘           └─┘
typ                                    └──────┘     └─────┘          └─┘
doc    └──┘                            └──────┘      └─────┘
2608  
2609  @[simp] theorem cons_ndinter_of_mem {a : α} (s : multiset α) {t : multiset α} (h : a ∈ t) :
id                                                   └──────┘        └──────┘          
src                                                   └──────┘         └──────┘           
typ                                                  └──────┘        └──────┘          
doc    └──┘                                           └──────┘         └──────┘
2610    ndinter (a::s) t = a :: (ndinter s t) := by simp [ndinter, h]
id     └─────┘  └┘     └┘  └─────┘                └─────┘  
src    └─────┘   └┘        └┘  └─────┘            └────┘└─────┘└┘ └─
typ    └─────┘  └┘     └┘  └─────┘          └────┘└─────┘└┘└─
doc    └─────┘   └┘         └┘  └─────┘            └────┘└─────┘└┘ └─
txt                                                └────┘       └┘ └─
par                                                └────┘       └┘ └─
pid                                                           └┘ 
st                                                └──────────────────
2611  
src  
typ  
doc  
txt  
par  
pid  
st   
2612  @[simp] theorem ndinter_cons_of_not_mem {a : α} (s : multiset α) {t : multiset α} (h : a ∉ t) :
id                                                       └──────┘        └──────┘          
src                                                       └──────┘         └──────┘           
typ                                                      └──────┘        └──────┘          
doc    └──┘                                               └──────┘         └──────┘
2613    ndinter (a::s) t = ndinter s t := by simp [ndinter, h]
id     └─────┘  └┘    └─────┘               └─────┘  
src    └─────┘   └┘      └─────┘           └────┘└─────┘└┘ └─
typ    └─────┘  └┘    └─────┘         └────┘└─────┘└┘└─
doc    └─────┘   └┘       └─────┘           └────┘└─────┘└┘ └─
txt                                         └────┘       └┘ └─
par                                         └────┘       └┘ └─
pid                                                    └┘ 
st                                         └──────────────────
2614  
src  
typ  
doc  
txt  
par  
pid  
st   
2615  @[simp] theorem mem_ndinter {s t : multiset α} {a : α} : a ∈ ndinter s t ↔ a ∈ s ∧ a ∈ t :=
id                                      └──────┘              └─────┘          
src                                     └──────┘                 └─────┘              
typ                                     └──────┘              └─────┘          
doc    └──┘                             └──────┘                  └─────┘
2616  mem_filter
id   └────────┘
src  └────────┘
typ  └────────┘
2617  
2618  theorem nodup_ndinter {s : multiset α} (t : multiset α) : nodup s → nodup (ndinter s t) :=
id                              └──────┘        └──────┘     └───┘    └───┘  └─────┘  
src                             └──────┘         └──────┘      └───┘     └───┘  └─────┘
typ                             └──────┘        └──────┘     └───┘    └───┘  └─────┘  
doc                             └──────┘         └──────┘      └───┘     └───┘  └─────┘
2619  nodup_filter _
id   └──────────┘
src  └──────────┘
typ  └──────────┘
2620  
2621  theorem le_ndinter {s t u : multiset α} : s ≤ ndinter t u ↔ s ≤ t ∧ s ⊆ u :=
id                               └──────┘       └─────┘          
src                              └──────┘         └─────┘              
typ                              └──────┘       └─────┘          
doc                              └──────┘          └─────┘
2622  by simp [ndinter, le_filter, subset_iff]
id            └─────┘  └───────┘  └────────┘
src     └────┘└─────┘└┘└───────┘└┘└────────┘└─
typ     └────┘└─────┘└┘└───────┘└┘└────────┘└─
doc     └────┘└─────┘└┘         └┘          └─
txt     └────┘       └┘         └┘          └─
par     └────┘       └┘         └┘          └─
pid                └┘         └┘          
st     └──────────────────────────────────────
2623  
src  
typ  
doc  
txt  
par  
pid  
st   
2624  theorem ndinter_le_left (s t : multiset α) : ndinter s t ≤ s :=
id                                  └──────┘     └─────┘    
src                                 └──────┘      └─────┘     
typ                                 └──────┘     └─────┘    
doc                                 └──────┘      └─────┘
2625  (le_ndinter.1 (le_refl _)).1
id    └────────┘   └─────┘    
src   └────────┘   └─────┘    
typ   └────────┘   └─────┘    
2626  
2627  theorem ndinter_subset_right (s t : multiset α) : ndinter s t ⊆ t :=
id                                       └──────┘     └─────┘    
src                                      └──────┘      └─────┘     
typ                                      └──────┘     └─────┘    
doc                                      └──────┘      └─────┘
2628  (le_ndinter.1 (le_refl _)).2
id    └────────┘   └─────┘    
src   └────────┘   └─────┘    
typ   └────────┘   └─────┘    
2629  
2630  theorem ndinter_le_right {s} (t : multiset α) (d : nodup s) : ndinter s t ≤ t :=
id                                     └──────┘        └───┘     └─────┘    
src                                    └──────┘         └───┘      └─────┘     
typ                                    └──────┘        └───┘     └─────┘    
doc                                    └──────┘         └───┘      └─────┘
2631  (le_iff_subset $ nodup_ndinter _ d).2 (ndinter_subset_right _ _)
id    └───────────┘   └───────────┘       └──────────────────┘
src   └───────────┘   └───────────┘        └──────────────────┘
typ   └───────────┘   └───────────┘       └──────────────────┘
2632  
2633  theorem inter_le_ndinter (s t : multiset α) : s ∩ t ≤ ndinter s t :=
id                                   └──────┘         └─────┘  
src                                  └──────┘            └─────┘
typ                                  └──────┘         └─────┘  
doc                                  └──────┘              └─────┘
2634  le_ndinter.2 ⟨inter_le_left _ _, subset_of_le $ inter_le_right _ _⟩
id   └────────┘   └───────────┘      └──────────┘   └────────────┘
src  └────────┘   └───────────┘      └──────────┘   └────────────┘
typ  └────────┘   └───────────┘      └──────────┘   └────────────┘
2635  
2636  @[simp] theorem ndinter_eq_inter {s t : multiset α} (d : nodup s) : ndinter s t = s ∩ t :=
id                                           └──────┘        └───┘     └─────┘      
src                                          └──────┘         └───┘      └─────┘        
typ                                          └──────┘        └───┘     └─────┘      
doc    └──┘                                  └──────┘         └───┘      └─────┘
2637  le_antisymm (le_inter (ndinter_le_left _ _) (ndinter_le_right _ d)) (inter_le_ndinter _ _)
id   └─────────┘  └──────┘  └─────────────┘       └──────────────┘       └──────────────┘
src  └─────────┘  └──────┘  └─────────────┘       └──────────────┘        └──────────────┘
typ  └─────────┘  └──────┘  └─────────────┘       └──────────────┘       └──────────────┘
2638  
2639  theorem ndinter_eq_zero_iff_disjoint {s t : multiset α} : ndinter s t = 0 ↔ disjoint s t :=
id                                               └──────┘     └─────┘       └──────┘  
src                                              └──────┘      └─────┘         └──────┘
typ                                              └──────┘     └─────┘       └──────┘  
doc                                              └──────┘      └─────┘           └──────┘
2640  by rw ← subset_zero; simp [subset_iff, disjoint]
id           └─────────┘        └────────┘  └──────┘
src     └───┘└─────────┘  └────┘└────────┘└┘└──────┘└─
typ     └───┘└─────────┘  └────┘└────────┘└┘└──────┘└─
doc     └───┘             └────┘          └┘└──────┘└─
txt     └───┘             └────┘          └┘        └─
par     └───┘             └────┘          └┘        └─
pid       └─┘                           └┘        
st     └──────────────────────────────────────────────
2641  
src  
typ  
doc  
txt  
par  
pid  
st   
2642  end
2643  
2644  /- fold -/
2645  section fold
2646  variables (op : α → α → α) [hc : is_commutative α op] [ha : is_associative α op]
id                                    └────────────┘             └────────────┘
src                                   └────────────┘             └────────────┘
typ                                   └────────────┘             └────────────┘
2647  local notation a * b := op a b
2648  include hc ha
2649  
2650  /-- `fold op b s` folds a commutative associative operation `op` over
2651    the multiset `s`. -/
2652  def fold : α → multiset α → α := foldr op (left_comm _ hc.comm ha.assoc)
id                 └──────┘        └───┘ └┘  └───────┘   └┘└───┘ └┘└────┘
src                 └──────┘          └───┘     └───────┘     └───┘   └────┘
typ                └──────┘        └───┘ └┘  └───────┘   └┘└───┘ └┘└────┘
doc                 └──────┘          └───┘
2653  
2654  theorem fold_eq_foldr (b : α) (s : multiset α) : fold op b s = foldr op (left_comm _ hc.comm ha.assoc) b s := rfl
id                                     └──────┘     └──┘ └┘    └───┘ └┘  └───────┘   └┘└───┘ └┘└────┘       └─┘
src                                     └──────┘      └──┘         └───┘     └───────┘     └───┘   └────┘         └─┘
typ                                    └──────┘     └──┘ └┘    └───┘ └┘  └───────┘   └┘└───┘ └┘└────┘       └─┘
doc                                     └──────┘      └──┘          └───┘
2655  
2656  @[simp] theorem coe_fold_r (b : α) (l : list α) : fold op b l = l.foldr op b := rfl
id                                          └──┘     └──┘ └┘    └────┘ └┘     └─┘
src                                          └──┘      └──┘          └────┘         └─┘
typ                                         └──┘     └──┘ └┘    └────┘ └┘     └─┘
doc    └──┘                                            └──┘
2657  
2658  theorem coe_fold_l (b : α) (l : list α) : fold op b l = l.foldl op b :=
id                                  └──┘     └──┘ └┘    └────┘ └┘ 
src                                  └──┘      └──┘          └────┘
typ                                 └──┘     └──┘ └┘    └────┘ └┘ 
doc                                            └──┘
2659  (coe_foldr_swap op _ b l).trans $ by simp [hc.comm]
id    └────────────┘ └┘     └───┘
src   └────────────┘          └───┘       └────┘       └─
typ   └────────────┘ └┘     └───┘       └────┘└─────┘└─
doc                                       └────┘       └─
txt                                       └────┘       └─
par                                       └────┘       └─
pid                                                  
st                                       └───────────────
2660  
src  
typ  
doc  
txt  
par  
pid  
st   
2661  theorem fold_eq_foldl (b : α) (s : multiset α) : fold op b s = foldl op (right_comm _ hc.comm ha.assoc) b s :=
id                                     └──────┘     └──┘ └┘    └───┘ └┘  └────────┘   └┘└───┘ └┘└────┘   
src                                     └──────┘      └──┘         └───┘     └────────┘     └───┘   └────┘
typ                                    └──────┘     └──┘ └┘    └───┘ └┘  └────────┘   └┘└───┘ └┘└────┘   
doc                                     └──────┘      └──┘          └───┘
2662  quot.induction_on s $ λ l, coe_fold_l _ _ _
id   └───────────────┘        └────────┘
src  └───────────────┘          └────────┘
typ  └───────────────┘        └────────┘
2663  
2664  @[simp] theorem fold_zero (b : α) : (0 : multiset α).fold op b = b := rfl
id                                           └──────┘  └──┘  └┘       └─┘
src                                           └──────┘   └──┘             └─┘
typ                                          └──────┘  └──┘  └┘       └─┘
doc    └──┘                                   └──────┘   └──┘
2665  
2666  @[simp] theorem fold_cons_left : ∀ (b a : α) (s : multiset α),
id                                                    └──────┘ 
src                                                    └──────┘
typ                                                   └──────┘ 
doc    └──┘                                            └──────┘
2667    (a :: s).fold op b = a * s.fold op b := foldr_cons _ _
id       └┘  └──┘  └┘     └───┘ └┘     └────────┘
src       └┘   └──┘             └───┘         └────────┘
typ      └┘  └──┘  └┘     └───┘ └┘     └────────┘
doc       └┘   └──┘              └───┘
2668  
2669  theorem fold_cons_right (b a : α) (s : multiset α) : (a :: s).fold op b = s.fold op b * a :=
id                                         └──────┘       └┘  └──┘  └┘   └───┘ └┘   
src                                         └──────┘         └┘   └──┘         └───┘
typ                                        └──────┘       └┘  └──┘  └┘   └───┘ └┘   
doc                                         └──────┘         └┘   └──┘          └───┘
2670  by simp [hc.comm]
src     └────┘       └─
typ     └────┘└─────┘└─
doc     └────┘       └─
txt     └────┘       └─
par     └────┘       └─
pid                
st     └───────────────
2671  
src  
typ  
doc  
txt  
par  
pid  
st   
2672  theorem fold_cons'_right (b a : α) (s : multiset α) : (a :: s).fold op b = s.fold op (b * a) :=
id                                          └──────┘       └┘  └──┘  └┘   └───┘ └┘    
src                                          └──────┘         └┘   └──┘         └───┘
typ                                         └──────┘       └┘  └──┘  └┘   └───┘ └┘    
doc                                          └──────┘         └┘   └──┘          └───┘
2673  by rw [fold_eq_foldl, foldl_cons, ← fold_eq_foldl]
id          └───────────┘  └────────┘    └───────────┘
src     └──┘└───────────┘└┘└────────┘└──┘└───────────┘└─
typ     └──┘└───────────┘└┘└────────┘└──┘└───────────┘└─
doc     └──┘             └┘          └──┘             └─
txt     └──┘             └┘          └──┘             └─
par     └──┘             └┘          └──┘             └─
pid       └┘             └┘          └──┘             
st     └────────────────┘└──────────┘└───────────────┘
2674  
src  
typ  
doc  
txt  
par  
pid  
st   
2675  theorem fold_cons'_left (b a : α) (s : multiset α) : (a :: s).fold op b = s.fold op (a * b) :=
id                                         └──────┘       └┘  └──┘  └┘   └───┘ └┘    
src                                         └──────┘         └┘   └──┘         └───┘
typ                                        └──────┘       └┘  └──┘  └┘   └───┘ └┘    
doc                                         └──────┘         └┘   └──┘          └───┘
2676  by rw [fold_cons'_right, hc.comm]
id          └──────────────┘
src     └──┘└──────────────┘└┘       └─
typ     └──┘└──────────────┘└┘└─────┘└─
doc     └──┘                └┘       └─
txt     └──┘                └┘       └─
par     └──┘                └┘       └─
pid       └┘                └┘       
st     └───────────────────┘└───────┘
2677  
src  
typ  
doc  
txt  
par  
pid  
st   
2678  theorem fold_add (b₁ b₂ : α) (s₁ s₂ : multiset α) : (s₁ + s₂).fold op (b₁ * b₂) = s₁.fold op b₁ * s₂.fold op b₂ :=
id                                        └──────┘      └┘  └┘ └──┘  └┘  └┘  └┘   └┘└───┘ └┘ └┘  └┘└───┘ └┘ └┘
src                                        └──────┘              └──┘                  └───┘           └───┘
typ                                       └──────┘      └┘  └┘ └──┘  └┘  └┘  └┘   └┘└───┘ └┘ └┘  └┘└───┘ └┘ └┘
doc                                        └──────┘               └──┘                   └───┘           └───┘
2679  multiset.induction_on s₂
id   └───────────────────┘ └┘
src  └───────────────────┘
typ  └───────────────────┘ └┘
2680    (by rw [add_zero, fold_zero, ← fold_cons'_right, ← fold_cons_right op])
id             └──────┘  └───────┘    └──────────────┘    └─────────────┘ └┘
src        └──┘└──────┘└┘└───────┘└──┘└──────────────┘└──┘└─────────────┘  
typ        └──┘└──────┘└┘└───────┘└──┘└──────────────┘└──┘└─────────────┘└┘
doc        └──┘        └┘         └──┘                └──┘                 
txt        └──┘        └┘         └──┘                └──┘                 
par        └──┘        └┘         └──┘                └──┘                 
pid          └┘        └┘         └──┘                └──┘                 
st        └───────────┘└─────────┘└──────────────────┘└────────────────────┘
2681    (by simp {contextual := tt}; cc)
id                             └┘
src        └───┘ └────────────┘└┘  └┘
typ        └───┘ └────────────┘└┘  └┘
doc        └───┘ └────────────┘    └┘
txt        └───┘ └────────────┘    └┘
par        └───┘ └────────────┘    └┘
pid             └────────────┘  
st        └──────────────────────────┘
2682  
2683  theorem fold_singleton (b a : α) : (a::0 : multiset α).fold op b = a * b := by simp
id                                      └┘    └──────┘  └──┘  └┘     
src                                       └┘    └──────┘   └──┘                    └────
typ                                     └┘    └──────┘  └──┘  └┘            └────
doc                                       └┘    └──────┘   └──┘                     └────
txt                                                                                 └────
par                                                                                 └────
pid                                                                                     
st                                                                                 └─────
2684  
src  
typ  
doc  
txt  
par  
pid  
st   
2685  theorem fold_distrib {f g : β → α} (u₁ u₂ : α) (s : multiset β) :
id                                                    └──────┘ 
src                                                      └──────┘
typ                                                   └──────┘ 
doc                                                      └──────┘
2686    (s.map (λx, f x * g x)).fold op (u₁ * u₂) = (s.map f).fold op u₁ * (s.map g).fold op u₂ :=
id      └──┘           └──┘  └┘  └┘  └┘    └──┘  └──┘  └┘ └┘   └──┘  └──┘  └┘ └┘
src      └──┘                 └──┘                  └──┘   └──┘            └──┘   └──┘
typ     └──┘           └──┘  └┘  └┘  └┘    └──┘  └──┘  └┘ └┘   └──┘  └──┘  └┘ └┘
doc      └──┘                 └──┘                   └──┘   └──┘            └──┘   └──┘
2687  multiset.induction_on s (by simp) (by simp {contextual := tt}; cc)
id   └───────────────────┘                                    └┘
src  └───────────────────┘       └──┘      └───┘ └────────────┘└┘  └┘
typ  └───────────────────┘      └──┘      └───┘ └────────────┘└┘  └┘
doc                              └──┘      └───┘ └────────────┘    └┘
txt                              └──┘      └───┘ └────────────┘    └┘
par                              └──┘      └───┘ └────────────┘    └┘
pid                                             └────────────┘  
st                              └───┘     └──────────────────────────┘
2688  
2689  theorem fold_hom {op' : β → β → β} [is_commutative β op'] [is_associative β op']
id                                    └────────────┘  └─┘   └────────────┘  └─┘
src                                      └────────────┘         └────────────┘
typ                                   └────────────┘  └─┘   └────────────┘  └─┘
2690    {m : α → β} (hm : ∀x y, m (op x y) = op' (m x) (m y)) (b : α) (s : multiset α) :
id                           └┘     └─┘                      └──────┘ 
src                                                                      └──────┘
typ                          └┘     └─┘                      └──────┘ 
doc                                                                       └──────┘
2691    (s.map m).fold op' (m b) = m (s.fold op b) :=
id      └──┘  └──┘  └─┘        └───┘ └┘ 
src      └──┘   └──┘                 └───┘
typ     └──┘  └──┘  └─┘        └───┘ └┘ 
doc      └──┘   └──┘                  └───┘
2692  multiset.induction_on s (by simp) (by simp [hm] {contextual := tt})
id   └───────────────────┘                      └┘                 └┘
src  └───────────────────┘       └──┘      └────┘  └┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └────┘└┘└┘ └────────────┘└┘
doc                              └──┘      └────┘  └┘ └────────────┘  
txt                              └──┘      └────┘  └┘ └────────────┘  
par                              └──┘      └────┘  └┘ └────────────┘  
pid                                               └────────────┘  
st                              └───┘     └───────────────────────────┘
2693  
2694  theorem fold_union_inter [decidable_eq α] (s₁ s₂ : multiset α) (b₁ b₂ : α) :
id                             └──────────┘            └──────┘            
src                            └──────────┘             └──────┘
typ                            └──────────┘            └──────┘            
doc                                                     └──────┘
2695    (s₁ ∪ s₂).fold op b₁ * (s₁ ∩ s₂).fold op b₂ = s₁.fold op b₁ * s₂.fold op b₂ :=
id      └┘  └┘ └──┘  └┘ └┘   └┘  └┘ └──┘  └┘ └┘  └┘└───┘ └┘ └┘  └┘└───┘ └┘ └┘
src            └──┘                  └──┘           └───┘           └───┘
typ     └┘  └┘ └──┘  └┘ └┘   └┘  └┘ └──┘  └┘ └┘  └┘└───┘ └┘ └┘  └┘└───┘ └┘ └┘
doc             └──┘                   └──┘            └───┘           └───┘
2696  by rw [← fold_add op, union_add_inter, fold_add op]
id            └──────┘ └┘  └─────────────┘  └──────┘ └┘
src     └────┘└──────┘  └┘└─────────────┘└┘└──────┘  └─
typ     └────┘└──────┘└┘└┘└─────────────┘└┘└──────┘└┘└─
doc     └────┘          └┘               └┘          └─
txt     └────┘          └┘               └┘          └─
par     └────┘          └┘               └┘          └─
pid       └──┘          └┘               └┘          
st     └────────────────┘└───────────────┘└───────────┘
2697  
src  
typ  
doc  
txt  
par  
pid  
st   
2698  @[simp] theorem fold_erase_dup_idem [decidable_eq α] [hi : is_idempotent α op] (s : multiset α) (b : α) :
id                                        └──────────┘         └───────────┘  └┘       └──────┘        
src                                       └──────────┘          └───────────┘            └──────┘
typ                                       └──────────┘         └───────────┘  └┘       └──────┘        
doc    └──┘                                                                              └──────┘
2699    (erase_dup s).fold op b = s.fold op b :=
id      └───────┘  └──┘  └┘   └───┘ └┘ 
src     └───────┘   └──┘         └───┘
typ     └───────┘  └──┘  └┘   └───┘ └┘ 
doc     └───────┘   └──┘          └───┘
2700  multiset.induction_on s (by simp) $ λ a s IH, begin
id   └───────────────────┘                  └┘
src  └───────────────────┘       └──┘
typ  └───────────────────┘      └──┘        └┘
doc                              └──┘
txt                              └──┘
par                              └──┘
st                              └───┘              └─────
2701    by_cases a ∈ s; simp [IH, h],
id                        └┘  
src    └───────┘    └────┘  └┘ 
typ    └───────┘  └────┘└┘└┘
doc    └───────┘     └────┘  └┘ 
txt    └───────┘     └────┘  └┘ 
par    └───────┘     └────┘  └┘ 
pid                       └┘ 
st   ─────────────────────────────┘└─
2702    show fold op b s = op a (fold op b s),
id                            └──┘ └┘  
src    └───┘            └──┘    
typ    └───┘           └──┘└┘
doc    └───┘             └──┘    
txt    └───┘                     
par    └───┘                     
pid    └───┘                     
st   ─────────────────────────────────────────
2703    rw [← cons_erase h, fold_cons_left, ← ha.assoc, hi.idempotent],
id           └────────┘   └────────────┘
src    └────┘└────────┘ └┘└────────────┘└──┘        └┘             
typ    └────┘└────────┘└┘└────────────┘└──┘└──────┘└┘└───────────┘
doc    └────┘           └┘              └──┘        └┘             
txt    └────┘           └┘              └──┘        └┘             
par    └────┘           └┘              └──┘        └┘             
pid      └──┘           └┘              └──┘        └┘             
st   ───────────────────┘└──────────────┘└──────────┘└─────────────┘└──
2704  end
st   ──┘
2705  
2706  end fold
2707  
2708  theorem le_smul_erase_dup [decidable_eq α] (s : multiset α) :
id                              └──────────┘        └──────┘ 
src                             └──────────┘         └──────┘
typ                             └──────────┘        └──────┘ 
doc                                                  └──────┘
2709    ∃ n : ℕ, s ≤ n • erase_dup s :=
id               └───────┘ 
src                └───────┘
typ              └───────┘ 
doc                     └───────┘
2710  ⟨(s.map (λ a, count a s)).fold max 0, le_iff_count.2 $ λ a, begin
id     └──┘      └───┘    └──┘  └─┘    └──────────┘      
src     └──┘       └───┘      └──┘  └─┘    └──────────┘
typ    └──┘      └───┘    └──┘  └─┘    └──────────┘      
doc     └──┘       └───┘      └──┘
st                                                               └─────
2711    rw count_smul, by_cases a ∈ s,
id        └────────┘             
src    └─┘└────────┘  └───────┘ 
typ    └─┘└────────┘  └───────┘
doc    └─┘            └───────┘  
txt    └─┘            └───────┘  
par    └─┘            └───────┘  
pid                            
st   ──────────────┘└──────────────┘└─
2712    { refine le_trans _ (mul_le_mul_left _ $ count_pos.2 $ mem_erase_dup.2 h),
id              └──────┘    └─────────────┘     └───────┘     └───────────┘   
src      └─────┘└──────┘└─┘ └─────────────┘└─┘ └───────┘└─┘ └───────────┘└─┘ 
typ      └─────┘└──────┘└─┘ └─────────────┘└─┘ └───────┘└─┘ └───────────┘└─┘
doc      └─────┘        └─┘                └─┘          └─┘              └─┘ 
txt      └─────┘        └─┘                └─┘          └─┘              └─┘ 
par      └─────┘        └─┘                └─┘          └─┘              └─┘ 
pid                    └─┘                └─┘          └─┘              └─┘ 
st   ───┘└─────────────────────────────────────────────────────────────────────┘└─
2713      have : count a s ≤ fold max 0 (map (λ a, count a s) (a :: erase s a));
id                         └──┘ └─┘    └─┘       └───┘         └┘ └───┘  
src      └─────┘       └──┘└─┘└─┘ └─┘  └──┘└───┘  └┘  └┘└───┘  └┘
typ      └─────┘       └──┘└─┘└─┘ └─┘  └──┘└───┘  └┘  └┘└───┘└┘
doc      └─────┘        └──┘   └─┘ └─┘  └──┘└───┘  └┘  └┘└───┘  └┘
txt      └─────┘               └─┘      └──┘       └┘           └┘
par      └─────┘               └─┘      └──┘       └┘           └┘
pid      └───┘└┘               └─┘      └──┘       └┘           └┘
st   ───────────────────────────────────────────────────────────────────────────
2714      [simp [le_max_left], simpa [cons_erase h]] },
id             └─────────┘          └────────┘ 
src      └────┘└─────────┘  └─────┘└────────┘ 
typ      └────┘└─────────┘  └─────┘└────────┘
doc       └────┘             └─────┘           
txt       └────┘             └─────┘           
par       └────┘             └─────┘           
pid                                        
st   ─────────────────────────────────────────────┘└─┘
2715    { simp [count_eq_zero.2 h, nat.zero_le] }
id             └───────────┘     └─────────┘
src      └────┘└───────────┘└─┘ └┘└─────────┘└┘
typ      └────┘└───────────┘└─┘└┘└─────────┘└┘
doc      └────┘             └─┘ └┘           └┘
txt      └────┘             └─┘ └┘           └┘
par      └────┘             └─┘ └┘           └┘
pid                       └─┘ └┘           
st   ─────────────────────────────────────────┘└─
2716  end⟩
st   ──┘
2717  
2718  section sup
2719  variables [semilattice_sup_bot α]
id              └─────────────────┘
src             └─────────────────┘
typ             └─────────────────┘
doc             └─────────────────┘
2720  
2721  /-- Supremum of a multiset: `sup {a, b, c} = a ⊔ b ⊔ c` -/
2722  def sup (s : multiset α) : α := s.fold (⊔) ⊥
id                └──────┘         └───┘    
src               └──────┘            └───┘    
typ               └──────┘         └───┘    
doc               └──────┘            └───┘
2723  
2724  @[simp] lemma sup_zero : (0 : multiset α).sup = ⊥ :=
id                                 └──────┘  └─┘   
src                                └──────┘   └─┘   
typ                                └──────┘  └─┘   
doc    └──┘                        └──────┘   └─┘
2725  fold_zero _ _
id   └───────┘
src  └───────┘
typ  └───────┘
2726  
2727  @[simp] lemma sup_cons (a : α) (s : multiset α) :
id                                      └──────┘ 
src                                      └──────┘
typ                                     └──────┘ 
doc    └──┘                              └──────┘
2728    (a :: s).sup = a ⊔ s.sup :=
id       └┘  └─┘     └──┘
src       └┘   └─┘       └──┘
typ      └┘  └─┘     └──┘
doc       └┘   └─┘         └──┘
2729  fold_cons_left _ _ _ _
id   └────────────┘
src  └────────────┘
typ  └────────────┘
2730  
2731  @[simp] lemma sup_singleton {a : α} : (a::0).sup = a := by simp
id                                         └┘  └─┘   
src                                          └┘  └─┘           └────
typ                                        └┘  └─┘          └────
doc    └──┘                                  └┘  └─┘            └────
txt                                                             └────
par                                                             └────
pid                                                                 
st                                                             └─────
2732  
src  
typ  
doc  
txt  
par  
pid  
st   
2733  @[simp] lemma sup_add (s₁ s₂ : multiset α) : (s₁ + s₂).sup = s₁.sup ⊔ s₂.sup :=
id                                  └──────┘      └┘  └┘ └─┘   └┘└──┘  └┘└──┘
src                                 └──────┘              └─┘     └──┘    └──┘
typ                                 └──────┘      └┘  └┘ └─┘   └┘└──┘  └┘└──┘
doc    └──┘                         └──────┘               └─┘      └──┘     └──┘
2734  eq.trans (by simp [sup]) (fold_add _ _ _ _ _)
id   └──────┘           └─┘    └──────┘
src  └──────┘     └────┘└─┘   └──────┘
typ  └──────┘     └────┘└─┘   └──────┘
doc               └────┘└─┘
txt               └────┘   
par               └────┘   
pid                      
st               └─────────┘
2735  
2736  variables [decidable_eq α]
id              └──────────┘
src             └──────────┘
typ             └──────────┘
2737  
2738  @[simp] lemma sup_erase_dup (s : multiset α) : (erase_dup s).sup = s.sup :=
id                                    └──────┘      └───────┘  └─┘   └──┘
src                                   └──────┘       └───────┘   └─┘    └──┘
typ                                   └──────┘      └───────┘  └─┘   └──┘
doc    └──┘                           └──────┘       └───────┘   └─┘     └──┘
2739  fold_erase_dup_idem _ _ _
id   └─────────────────┘
src  └─────────────────┘
typ  └─────────────────┘
2740  
2741  @[simp] lemma sup_ndunion (s₁ s₂ : multiset α) :
id                                      └──────┘ 
src                                     └──────┘
typ                                     └──────┘ 
doc    └──┘                             └──────┘
2742    (ndunion s₁ s₂).sup = s₁.sup ⊔ s₂.sup :=
id      └─────┘ └┘ └┘ └─┘   └┘└──┘  └┘└──┘
src     └─────┘       └─┘     └──┘    └──┘
typ     └─────┘ └┘ └┘ └─┘   └┘└──┘  └┘└──┘
doc     └─────┘       └─┘      └──┘     └──┘
2743  by rw [← sup_erase_dup, erase_dup_ext.2, sup_erase_dup, sup_add]; simp
id            └───────────┘  └───────────┘    └───────────┘  └─────┘
src     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└─────┘  └────
typ     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└─────┘  └────
doc     └────┘             └┘             └──┘             └┘         └────
txt     └────┘             └┘             └──┘             └┘         └────
par     └────┘             └┘             └──┘             └┘         └────
pid       └──┘             └┘             └──┘             └┘             
st     └──────────────────┘└─────────────┘└───────────────┘└───────┘└──────
2744  
src  
typ  
doc  
txt  
par  
pid  
st   
2745  @[simp] lemma sup_union (s₁ s₂ : multiset α) :
id                                    └──────┘ 
src                                   └──────┘
typ                                   └──────┘ 
doc    └──┘                           └──────┘
2746    (s₁ ∪ s₂).sup = s₁.sup ⊔ s₂.sup :=
id      └┘  └┘ └─┘   └┘└──┘  └┘└──┘
src            └─┘     └──┘    └──┘
typ     └┘  └┘ └─┘   └┘└──┘  └┘└──┘
doc             └─┘      └──┘     └──┘
2747  by rw [← sup_erase_dup, erase_dup_ext.2, sup_erase_dup, sup_add]; simp
id            └───────────┘  └───────────┘    └───────────┘  └─────┘
src     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└─────┘  └────
typ     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└─────┘  └────
doc     └────┘             └┘             └──┘             └┘         └────
txt     └────┘             └┘             └──┘             └┘         └────
par     └────┘             └┘             └──┘             └┘         └────
pid       └──┘             └┘             └──┘             └┘             
st     └──────────────────┘└─────────────┘└───────────────┘└───────┘└──────
2748  
src  
typ  
doc  
txt  
par  
pid  
st   
2749  @[simp] lemma sup_ndinsert (a : α) (s : multiset α) :
id                                          └──────┘ 
src                                          └──────┘
typ                                         └──────┘ 
doc    └──┘                                  └──────┘
2750    (ndinsert a s).sup = a ⊔ s.sup :=
id      └──────┘   └─┘     └──┘
src     └──────┘     └─┘       └──┘
typ     └──────┘   └─┘     └──┘
doc     └──────┘     └─┘         └──┘
2751  by rw [← sup_erase_dup, erase_dup_ext.2, sup_erase_dup, sup_cons]; simp
id            └───────────┘  └───────────┘    └───────────┘  └──────┘
src     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└──────┘  └────
typ     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└──────┘  └────
doc     └────┘             └┘             └──┘             └┘          └────
txt     └────┘             └┘             └──┘             └┘          └────
par     └────┘             └┘             └──┘             └┘          └────
pid       └──┘             └┘             └──┘             └┘              
st     └──────────────────┘└─────────────┘└───────────────┘└────────┘└──────
2752  
src  
typ  
doc  
txt  
par  
pid  
st   
2753  lemma sup_le {s : multiset α} {a : α} : s.sup ≤ a ↔ (∀b ∈ s, b ≤ a) :=
id                     └──────┘            └──┘             
src                    └──────┘               └──┘                
typ                    └──────┘            └──┘             
doc                    └──────┘               └──┘
2754  multiset.induction_on s (by simp)
id   └───────────────────┘ 
src  └───────────────────┘       └──┘
typ  └───────────────────┘      └──┘
doc                              └──┘
txt                              └──┘
par                              └──┘
st                              └───┘
2755    (by simp [or_imp_distrib, forall_and_distrib] {contextual := tt})
id               └────────────┘  └────────────────┘                 └┘
src        └────┘└────────────┘└┘└────────────────┘└┘ └────────────┘└┘
typ        └────┘└────────────┘└┘└────────────────┘└┘ └────────────┘└┘
doc        └────┘              └┘                  └┘ └────────────┘  
txt        └────┘              └┘                  └┘ └────────────┘  
par        └────┘              └┘                  └┘ └────────────┘  
pid                          └┘                   └────────────┘  
st        └───────────────────────────────────────────────────────────┘
2756  
2757  lemma le_sup {s : multiset α} {a : α} (h : a ∈ s) : a ≤ s.sup :=
id                     └──────┘                       └──┘
src                    └──────┘                             └──┘
typ                    └──────┘                       └──┘
doc                    └──────┘                               └──┘
2758  sup_le.1 (le_refl _) _ h
id   └────┘   └─────┘      
src  └────┘   └─────┘
typ  └────┘   └─────┘      
2759  
2760  lemma sup_mono {s₁ s₂ : multiset α} (h : s₁ ⊆ s₂) : s₁.sup ≤ s₂.sup :=
id                           └──────┘        └┘  └┘    └┘└──┘  └┘└──┘
src                          └──────┘                     └──┘    └──┘
typ                          └──────┘        └┘  └┘    └┘└──┘  └┘└──┘
doc                          └──────┘                      └──┘     └──┘
2761  sup_le.2 $ assume b hb, le_sup (h hb)
id   └────┘            └┘  └────┘   └┘
src  └────┘                 └────┘
typ  └────┘            └┘  └────┘   └┘
2762  
2763  end sup
2764  
2765  section inf
2766  variables [semilattice_inf_top α]
id              └─────────────────┘
src             └─────────────────┘
typ             └─────────────────┘
doc             └─────────────────┘
2767  
2768  /-- Infimum of a multiset: `inf {a, b, c} = a ⊓ b ⊓ c` -/
2769  def inf (s : multiset α) : α := s.fold (⊓) ⊤
id                └──────┘         └───┘    
src               └──────┘            └───┘    
typ               └──────┘         └───┘    
doc               └──────┘            └───┘
2770  
2771  @[simp] lemma inf_zero : (0 : multiset α).inf = ⊤ :=
id                                 └──────┘  └─┘   
src                                └──────┘   └─┘   
typ                                └──────┘  └─┘   
doc    └──┘                        └──────┘   └─┘
2772  fold_zero _ _
id   └───────┘
src  └───────┘
typ  └───────┘
2773  
2774  @[simp] lemma inf_cons (a : α) (s : multiset α) :
id                                      └──────┘ 
src                                      └──────┘
typ                                     └──────┘ 
doc    └──┘                              └──────┘
2775    (a :: s).inf = a ⊓ s.inf :=
id       └┘  └─┘     └──┘
src       └┘   └─┘       └──┘
typ      └┘  └─┘     └──┘
doc       └┘   └─┘         └──┘
2776  fold_cons_left _ _ _ _
id   └────────────┘
src  └────────────┘
typ  └────────────┘
2777  
2778  @[simp] lemma inf_singleton {a : α} : (a::0).inf = a := by simp
id                                         └┘  └─┘   
src                                          └┘  └─┘           └────
typ                                        └┘  └─┘          └────
doc    └──┘                                  └┘  └─┘            └────
txt                                                             └────
par                                                             └────
pid                                                                 
st                                                             └─────
2779  
src  
typ  
doc  
txt  
par  
pid  
st   
2780  @[simp] lemma inf_add (s₁ s₂ : multiset α) : (s₁ + s₂).inf = s₁.inf ⊓ s₂.inf :=
id                                  └──────┘      └┘  └┘ └─┘   └┘└──┘  └┘└──┘
src                                 └──────┘              └─┘     └──┘    └──┘
typ                                 └──────┘      └┘  └┘ └─┘   └┘└──┘  └┘└──┘
doc    └──┘                         └──────┘               └─┘      └──┘     └──┘
2781  eq.trans (by simp [inf]) (fold_add _ _ _ _ _)
id   └──────┘           └─┘    └──────┘
src  └──────┘     └────┘└─┘   └──────┘
typ  └──────┘     └────┘└─┘   └──────┘
doc               └────┘└─┘
txt               └────┘   
par               └────┘   
pid                      
st               └─────────┘
2782  
2783  variables [decidable_eq α]
id              └──────────┘
src             └──────────┘
typ             └──────────┘
2784  
2785  @[simp] lemma inf_erase_dup (s : multiset α) : (erase_dup s).inf = s.inf :=
id                                    └──────┘      └───────┘  └─┘   └──┘
src                                   └──────┘       └───────┘   └─┘    └──┘
typ                                   └──────┘      └───────┘  └─┘   └──┘
doc    └──┘                           └──────┘       └───────┘   └─┘     └──┘
2786  fold_erase_dup_idem _ _ _
id   └─────────────────┘
src  └─────────────────┘
typ  └─────────────────┘
2787  
2788  @[simp] lemma inf_ndunion (s₁ s₂ : multiset α) :
id                                      └──────┘ 
src                                     └──────┘
typ                                     └──────┘ 
doc    └──┘                             └──────┘
2789    (ndunion s₁ s₂).inf = s₁.inf ⊓ s₂.inf :=
id      └─────┘ └┘ └┘ └─┘   └┘└──┘  └┘└──┘
src     └─────┘       └─┘     └──┘    └──┘
typ     └─────┘ └┘ └┘ └─┘   └┘└──┘  └┘└──┘
doc     └─────┘       └─┘      └──┘     └──┘
2790  by rw [← inf_erase_dup, erase_dup_ext.2, inf_erase_dup, inf_add]; simp
id            └───────────┘  └───────────┘    └───────────┘  └─────┘
src     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└─────┘  └────
typ     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└─────┘  └────
doc     └────┘             └┘             └──┘             └┘         └────
txt     └────┘             └┘             └──┘             └┘         └────
par     └────┘             └┘             └──┘             └┘         └────
pid       └──┘             └┘             └──┘             └┘             
st     └──────────────────┘└─────────────┘└───────────────┘└───────┘└──────
2791  
src  
typ  
doc  
txt  
par  
pid  
st   
2792  @[simp] lemma inf_union (s₁ s₂ : multiset α) :
id                                    └──────┘ 
src                                   └──────┘
typ                                   └──────┘ 
doc    └──┘                           └──────┘
2793    (s₁ ∪ s₂).inf = s₁.inf ⊓ s₂.inf :=
id      └┘  └┘ └─┘   └┘└──┘  └┘└──┘
src            └─┘     └──┘    └──┘
typ     └┘  └┘ └─┘   └┘└──┘  └┘└──┘
doc             └─┘      └──┘     └──┘
2794  by rw [← inf_erase_dup, erase_dup_ext.2, inf_erase_dup, inf_add]; simp
id            └───────────┘  └───────────┘    └───────────┘  └─────┘
src     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└─────┘  └────
typ     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└─────┘  └────
doc     └────┘             └┘             └──┘             └┘         └────
txt     └────┘             └┘             └──┘             └┘         └────
par     └────┘             └┘             └──┘             └┘         └────
pid       └──┘             └┘             └──┘             └┘             
st     └──────────────────┘└─────────────┘└───────────────┘└───────┘└──────
2795  
src  
typ  
doc  
txt  
par  
pid  
st   
2796  @[simp] lemma inf_ndinsert (a : α) (s : multiset α) :
id                                          └──────┘ 
src                                          └──────┘
typ                                         └──────┘ 
doc    └──┘                                  └──────┘
2797    (ndinsert a s).inf = a ⊓ s.inf :=
id      └──────┘   └─┘     └──┘
src     └──────┘     └─┘       └──┘
typ     └──────┘   └─┘     └──┘
doc     └──────┘     └─┘         └──┘
2798  by rw [← inf_erase_dup, erase_dup_ext.2, inf_erase_dup, inf_cons]; simp
id            └───────────┘  └───────────┘    └───────────┘  └──────┘
src     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└──────┘  └────
typ     └────┘└───────────┘└┘└───────────┘└──┘└───────────┘└┘└──────┘  └────
doc     └────┘             └┘             └──┘             └┘          └────
txt     └────┘             └┘             └──┘             └┘          └────
par     └────┘             └┘             └──┘             └┘          └────
pid       └──┘             └┘             └──┘             └┘              
st     └──────────────────┘└─────────────┘└───────────────┘└────────┘└──────
2799  
src  
typ  
doc  
txt  
par  
pid  
st   
2800  lemma le_inf {s : multiset α} {a : α} : a ≤ s.inf ↔ (∀b ∈ s, a ≤ b) :=
id                     └──────┘              └──┘           
src                    └──────┘                  └──┘             
typ                    └──────┘              └──┘           
doc                    └──────┘                   └──┘
2801  multiset.induction_on s (by simp)
id   └───────────────────┘ 
src  └───────────────────┘       └──┘
typ  └───────────────────┘      └──┘
doc                              └──┘
txt                              └──┘
par                              └──┘
st                              └───┘
2802    (by simp [or_imp_distrib, forall_and_distrib] {contextual := tt})
id               └────────────┘  └────────────────┘                 └┘
src        └────┘└────────────┘└┘└────────────────┘└┘ └────────────┘└┘
typ        └────┘└────────────┘└┘└────────────────┘└┘ └────────────┘└┘
doc        └────┘              └┘                  └┘ └────────────┘  
txt        └────┘              └┘                  └┘ └────────────┘  
par        └────┘              └┘                  └┘ └────────────┘  
pid                          └┘                   └────────────┘  
st        └───────────────────────────────────────────────────────────┘
2803  
2804  lemma inf_le {s : multiset α} {a : α} (h : a ∈ s) : s.inf ≤ a :=
id                     └──────┘                     └──┘  
src                    └──────┘                          └──┘ 
typ                    └──────┘                     └──┘  
doc                    └──────┘                           └──┘
2805  le_inf.1 (le_refl _) _ h
id   └────┘   └─────┘      
src  └────┘   └─────┘
typ  └────┘   └─────┘      
2806  
2807  lemma inf_mono {s₁ s₂ : multiset α} (h : s₁ ⊆ s₂) : s₂.inf ≤ s₁.inf :=
id                           └──────┘        └┘  └┘    └┘└──┘  └┘└──┘
src                          └──────┘                     └──┘    └──┘
typ                          └──────┘        └┘  └┘    └┘└──┘  └┘└──┘
doc                          └──────┘                      └──┘     └──┘
2808  le_inf.2 $ assume b hb, inf_le (h hb)
id   └────┘            └┘  └────┘   └┘
src  └────┘                 └────┘
typ  └────┘            └┘  └────┘   └┘
2809  
2810  end inf
2811  
2812  section sort
2813  variables (r : α → α → Prop) [decidable_rel r]
id                                 └───────────┘
src                                └───────────┘
typ                                └───────────┘
2814    [is_trans α r] [is_antisymm α r] [is_total α r]
id      └──────┘       └─────────┘       └──────┘
src     └──────┘       └─────────┘       └──────┘
typ     └──────┘       └─────────┘       └──────┘
2815  
2816  /-- `sort s` constructs a sorted list from the multiset `s`.
2817    (Uses merge sort algorithm.) -/
2818  def sort (s : multiset α) : list α :=
id                 └──────┘     └──┘ 
src                └──────┘      └──┘
typ                └──────┘     └──┘ 
doc                └──────┘
2819  quot.lift_on s (merge_sort r) $ λ a b h,
id   └──────────┘   └────────┘         
src  └──────────┘    └────────┘
typ  └──────────┘   └────────┘         
doc                  └────────┘
2820  eq_of_sorted_of_perm
id   └──────────────────┘
src  └──────────────────┘
typ  └──────────────────┘
2821    ((perm_merge_sort _ _).trans $ h.trans (perm_merge_sort _ _).symm)
id       └─────────────┘     └───┘    └────┘  └─────────────┘     └──┘
src      └─────────────┘     └───┘     └────┘  └─────────────┘     └──┘
typ      └─────────────┘     └───┘    └────┘  └─────────────┘     └──┘
2822    (sorted_merge_sort r _)
id      └───────────────┘ 
src     └───────────────┘
typ     └───────────────┘ 
2823    (sorted_merge_sort r _)
id      └───────────────┘ 
src     └───────────────┘
typ     └───────────────┘ 
2824  
2825  @[simp] theorem coe_sort (l : list α) : sort r l = merge_sort r l := rfl
id                                 └──┘     └──┘    └────────┘      └─┘
src                                └──┘      └──┘      └────────┘        └─┘
typ                                └──┘     └──┘    └────────┘      └─┘
doc    └──┘                                  └──┘       └────────┘
2826  
2827  @[simp] theorem sort_sorted (s : multiset α) : sorted r (sort r s) :=
id                                    └──────┘     └────┘   └──┘  
src                                   └──────┘      └────┘    └──┘
typ                                   └──────┘     └────┘   └──┘  
doc    └──┘                           └──────┘      └────┘    └──┘
2828  quot.induction_on s $ λ l, sorted_merge_sort r _
id   └───────────────┘        └───────────────┘ 
src  └───────────────┘          └───────────────┘
typ  └───────────────┘        └───────────────┘ 
2829  
2830  @[simp] theorem sort_eq (s : multiset α) : ↑(sort r s) = s :=
id                                └──────┘      └──┘     
src                               └──────┘       └──┘      
typ                               └──────┘      └──┘     
doc    └──┘                       └──────┘        └──┘
2831  quot.induction_on s $ λ l, quot.sound $ perm_merge_sort _ _
id   └───────────────┘        └────────┘   └─────────────┘
src  └───────────────┘          └────────┘   └─────────────┘
typ  └───────────────┘        └────────┘   └─────────────┘
2832  
2833  @[simp] theorem mem_sort {s : multiset α} {a : α} : a ∈ sort r s ↔ a ∈ s :=
id                                 └──────┘              └──┘      
src                                └──────┘                 └──┘        
typ                                └──────┘              └──┘      
doc    └──┘                        └──────┘                  └──┘
2834  by rw [← mem_coe, sort_eq]
id            └─────┘  └─────┘
src     └────┘└─────┘└┘└─────┘└─
typ     └────┘└─────┘└┘└─────┘└─
doc     └────┘       └┘       └─
txt     └────┘       └┘       └─
par     └────┘       └┘       └─
pid       └──┘       └┘       
st     └────────────┘└───────┘
2835  
src  
typ  
doc  
txt  
par  
pid  
st   
2836  @[simp] theorem length_sort {s : multiset α} : (sort r s).length = s.card :=
id                                    └──────┘      └──┘   └────┘   └───┘
src                                   └──────┘       └──┘     └────┘    └───┘
typ                                   └──────┘      └──┘   └────┘   └───┘
doc    └──┘                           └──────┘       └──┘                └───┘
2837  quot.induction_on s $ length_merge_sort _
id   └───────────────┘    └───────────────┘
src  └───────────────┘     └───────────────┘
typ  └───────────────┘    └───────────────┘
2838  
2839  end sort
2840  
2841  instance [has_repr α] : has_repr (multiset α) :=
id             └──────┘     └──────┘  └──────┘ 
src            └──────┘      └──────┘  └──────┘
typ            └──────┘     └──────┘  └──────┘ 
doc                                    └──────┘
2842  ⟨λ s, "{" ++ string.intercalate ", " ((s.map repr).sort (≤)) ++ "}"⟩
id            └┘ └────────────────┘        └──┘ └──┘ └──┘      └┘
src            └┘ └────────────────┘         └──┘ └──┘ └──┘      └┘
typ           └┘ └────────────────┘        └──┘ └──┘ └──┘      └┘
doc                                          └──┘      └──┘
2843  
2844  section sections
2845  
2846  def sections (s : multiset (multiset α)) : multiset (multiset α) :=
id                     └──────┘  └──────┘      └──────┘  └──────┘ 
src                    └──────┘  └──────┘       └──────┘  └──────┘
typ                    └──────┘  └──────┘      └──────┘  └──────┘ 
doc                    └──────┘  └──────┘       └──────┘  └──────┘
2847  multiset.rec_on s {0} (λs _ c, s.bind $ λa, c.map ((::) a))
id   └─────────────┘           └───┘      └──┘  └──┘ 
src  └─────────────┘                └───┘        └──┘  └──┘
typ  └─────────────┘           └───┘      └──┘  └──┘ 
doc                                  └───┘        └──┘  └──┘
2848    (assume a₀ a₁ s pi, by simp [map_bind, bind_bind a₀ a₁, cons_swap])
id             └┘ └┘  └┘           └──────┘  └───────┘ └┘ └┘  └───────┘
src                           └────┘└──────┘└┘└───────┘    └┘└───────┘
typ            └┘ └┘  └┘     └────┘└──────┘└┘└───────┘└┘└┘└┘└───────┘
doc                           └────┘        └┘             └┘         
txt                           └────┘        └┘             └┘         
par                           └────┘        └┘             └┘         
pid                                       └┘             └┘         
st                           └──────────────────────────────────────────┘
2849  
2850  @[simp] lemma sections_zero : sections (0 : multiset (multiset α)) = 0::0 :=
id                                 └──────┘      └──────┘  └──────┘      └┘
src                                └──────┘      └──────┘  └──────┘       └┘
typ                                └──────┘      └──────┘  └──────┘      └┘
doc    └──┘                                      └──────┘  └──────┘        └┘
2851  rfl
id   └─┘
src  └─┘
typ  └─┘
2852  
2853  @[simp] lemma sections_cons (s : multiset (multiset α)) (m : multiset α) :
id                                    └──────┘  └──────┘         └──────┘ 
src                                   └──────┘  └──────┘          └──────┘
typ                                   └──────┘  └──────┘         └──────┘ 
doc    └──┘                           └──────┘  └──────┘          └──────┘
2854    sections (m :: s) = m.bind (λa, (sections s).map ((::) a)) :=
id     └──────┘   └┘    └───┘      └──────┘  └─┘   └──┘ 
src    └──────┘    └┘      └───┘       └──────┘   └─┘   └──┘
typ    └──────┘   └┘    └───┘      └──────┘  └─┘   └──┘ 
doc                └┘       └───┘                  └─┘   └──┘
2855  rec_on_cons m s
id   └─────────┘  
src  └─────────┘
typ  └─────────┘  
2856  
2857  lemma coe_sections : ∀(l : list (list α)),
id                             └──┘  └──┘ 
src                             └──┘  └──┘
typ                            └──┘  └──┘ 
2858    sections ((l.map (λl:list α, (l : multiset α))) : multiset (multiset α)) =
id     └──────┘   └──┘     └──┘       └──────┘       └──────┘  └──────┘    
src    └──────┘    └──┘     └──┘         └──────┘        └──────┘  └──────┘     
typ    └──────┘   └──┘     └──┘       └──────┘       └──────┘  └──────┘    
doc                                      └──────┘        └──────┘  └──────┘
2859      ((l.sections.map (λl:list α, (l : multiset α))) : multiset (multiset α))
id         └───────┘└──┘     └──┘       └──────┘       └──────┘  └──────┘ 
src         └───────┘└──┘     └──┘         └──────┘        └──────┘  └──────┘
typ        └───────┘└──┘     └──┘       └──────┘       └──────┘  └──────┘ 
doc         └───────┘                      └──────┘        └──────┘  └──────┘
2860  | [] := rfl
id     └┘    └─┘
src    └┘    └─┘
typ    └┘    └─┘
2861  | (a :: l) :=
id        └┘
src       └┘
typ       └┘
2862    begin
st     └─────
2863      simp,
src      └──┘
typ      └──┘
doc      └──┘
txt      └──┘
par      └──┘
st   ───────┘└─
2864      rw [← cons_coe, sections_cons, bind_map_comm, coe_sections l],
id             └──────┘  └───────────┘  └───────────┘  └──────────┘ 
src      └────┘└──────┘└┘└───────────┘└┘└───────────┘└┘             
typ      └────┘└──────┘└┘└───────────┘└┘└───────────┘└┘└──────────┘
doc      └────┘        └┘             └┘             └┘             
txt      └────┘        └┘             └┘             └┘             
par      └────┘        └┘             └┘             └┘             
pid        └──┘        └┘             └┘             └┘             
st   ─────────────────┘└─────────────┘└─────────────┘└──────────────┘└──
2865      simp [list.sections, (∘), list.bind]
id             └───────────┘      └───────┘
src      └────┘└───────────┘└┘└──┘└───────┘└─
typ      └────┘└───────────┘└┘└──┘└───────┘└─
doc      └────┘└───────────┘└┘ └──┘         └─
txt      └────┘             └┘ └──┘         └─
par      └────┘             └┘ └──┘         └─
pid                       └┘ └──┘         
st   ─────────────────────────────────────────
2866    end
src  ─┘
typ  ─┘
doc  ─┘
txt  ─┘
par  ─┘
pid  ─┘
st   ─┘└─┘
2867  
2868  @[simp] lemma sections_add (s t : multiset (multiset α)) :
id                                     └──────┘  └──────┘ 
src                                    └──────┘  └──────┘
typ                                    └──────┘  └──────┘ 
doc    └──┘                            └──────┘  └──────┘
2869    sections (s + t) = (sections s).bind (λm, (sections t).map ((+) m)) :=
id     └──────┘        └──────┘  └──┘       └──────┘  └─┘      
src    └──────┘          └──────┘   └──┘        └──────┘   └─┘   
typ    └──────┘        └──────┘  └──┘       └──────┘  └─┘      
doc                                   └──┘                   └─┘
2870  multiset.induction_on s (by simp)
id   └───────────────────┘ 
src  └───────────────────┘       └──┘
typ  └───────────────────┘      └──┘
doc                              └──┘
txt                              └──┘
par                              └──┘
st                              └───┘
2871    (assume a s ih, by simp [ih, bind_assoc, map_bind, bind_map, -add_comm])
id               └┘           └┘  └────────┘  └──────┘  └──────┘
src                       └────┘  └┘└────────┘└┘└──────┘└┘└──────┘└──────────┘
typ              └┘     └────┘└┘└┘└────────┘└┘└──────┘└┘└──────┘└──────────┘
doc                       └────┘  └┘          └┘        └┘        └──────────┘
txt                       └────┘  └┘          └┘        └┘        └──────────┘
par                       └────┘  └┘          └┘        └┘        └──────────┘
pid                             └┘          └┘        └┘        └──────────┘
st                       └───────────────────────────────────────────────────┘
2872  
2873  lemma mem_sections {s : multiset (multiset α)} :
id                           └──────┘  └──────┘ 
src                          └──────┘  └──────┘
typ                          └──────┘  └──────┘ 
doc                          └──────┘  └──────┘
2874    ∀{a}, a ∈ sections s ↔ s.rel (λs a, a ∈ s) a :=
id            └──────┘   └──┘          
src             └──────┘     └──┘          
typ           └──────┘   └──┘          
doc                            └──┘
2875  multiset.induction_on s (by simp)
id   └───────────────────┘ 
src  └───────────────────┘       └──┘
typ  └───────────────────┘      └──┘
doc                              └──┘
txt                              └──┘
par                              └──┘
st                              └───┘
2876    (assume a s ih a',
id               └┘ └┘
typ              └┘ └┘
2877      by simp [ih, rel_cons_left, -exists_and_distrib_left, exists_and_distrib_left.symm, eq_comm])
id                    └───────────┘                                                          └─────┘
src         └────┘  └┘└───────────┘└──────────────────────────┘                            └┘└─────┘
typ         └────┘└┘└┘└───────────┘└──────────────────────────┘└──────────────────────────┘└┘└─────┘
doc         └────┘  └┘             └──────────────────────────┘                            └┘       
txt         └────┘  └┘             └──────────────────────────┘                            └┘       
par         └────┘  └┘             └──────────────────────────┘                            └┘       
pid               └┘             └──────────────────────────┘                            └┘       
st         └────────────────────────────────────────────────────────────────────────────────────────┘
2878  
2879  lemma card_sections {s : multiset (multiset α)} : card (sections s) = prod (s.map card) :=
id                            └──────┘  └──────┘      └──┘  └──────┘    └──┘  └──┘ └──┘
src                           └──────┘  └──────┘       └──┘  └──────┘     └──┘   └──┘ └──┘
typ                           └──────┘  └──────┘      └──┘  └──────┘    └──┘  └──┘ └──┘
doc                           └──────┘  └──────┘       └──┘                └──┘   └──┘ └──┘
2880  multiset.induction_on s (by simp) (by simp {contextual := tt})
id   └───────────────────┘                                    └┘
src  └───────────────────┘       └──┘      └───┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └───┘ └────────────┘└┘
doc                              └──┘      └───┘ └────────────┘  
txt                              └──┘      └───┘ └────────────┘  
par                              └──┘      └───┘ └────────────┘  
pid                                             └────────────┘  
st                              └───┘     └──────────────────────┘
2881  
2882  lemma prod_map_sum [comm_semiring α] {s : multiset (multiset α)} :
id                       └───────────┘        └──────┘  └──────┘ 
src                      └───────────┘         └──────┘  └──────┘
typ                      └───────────┘        └──────┘  └──────┘ 
doc                                            └──────┘  └──────┘
2883    prod (s.map sum) = sum ((sections s).map prod) :=
id     └──┘  └──┘ └─┘   └─┘   └──────┘  └─┘  └──┘
src    └──┘   └──┘ └─┘   └─┘   └──────┘   └─┘  └──┘
typ    └──┘  └──┘ └─┘   └─┘   └──────┘  └─┘  └──┘
doc    └──┘   └──┘                         └─┘  └──┘
2884  multiset.induction_on s (by simp)
id   └───────────────────┘ 
src  └───────────────────┘       └──┘
typ  └───────────────────┘      └──┘
doc                              └──┘
txt                              └──┘
par                              └──┘
st                              └───┘
2885    (assume a s ih, by simp [ih, map_bind, sum_map_mul_left, sum_map_mul_right])
id               └┘           └┘  └──────┘  └──────────────┘  └───────────────┘
src                       └────┘  └┘└──────┘└┘└──────────────┘└┘└───────────────┘
typ              └┘     └────┘└┘└┘└──────┘└┘└──────────────┘└┘└───────────────┘
doc                       └────┘  └┘        └┘                └┘                 
txt                       └────┘  └┘        └┘                └┘                 
par                       └────┘  └┘        └┘                └┘                 
pid                             └┘        └┘                └┘                 
st                       └───────────────────────────────────────────────────────┘
2886  
2887  end sections
2888  
2889  section pi
2890  variables [decidable_eq α] {δ : α → Type*}
id              └──────────┘
src             └──────────┘
typ             └──────────┘
2891  open function
2892  
2893  def pi.cons (m : multiset α) (a : α) (b : δ a) (f : Πa∈m, δ a) : Πa'∈a::m, δ a' :=
id                    └──────┘                                 └┘ └┘   └┘
src                   └──────┘                                             └┘
typ                   └──────┘                                 └┘ └┘   └┘
doc                   └──────┘                                             └┘
2894  λa' ha', if h : a' = a then eq.rec b h.symm else f a' $ (mem_cons.1 ha').resolve_left h
id    └┘ └─┘  └┘     └┘        └────┘  └───┘       └┘   └──────┘  └─┘ └──────────┘  
src           └┘                └────┘    └───┘              └──────┘      └──────────┘
typ   └┘ └─┘  └┘     └┘        └────┘  └───┘       └┘   └──────┘  └─┘ └──────────┘  
2895  
2896  def pi.empty (δ : α → Type*) : (Πa∈(0:multiset α), δ a) .
id                                       └──────┘     
src                                        └──────┘
typ                                      └──────┘     
doc                                        └──────┘
2897  
2898  lemma pi.cons_same {m : multiset α} {a : α} {b : δ a} {f : Πa∈m, δ a} (h : a ∈ a :: m) :
id                           └──────┘                                      └┘ 
src                          └──────┘                                                └┘
typ                          └──────┘                                      └┘ 
doc                          └──────┘                                                 └┘
2899    pi.cons m a b f a h = b :=
id     └─────┘        
src    └─────┘             
typ    └─────┘        
2900  dif_pos rfl
id   └─────┘ └─┘
src  └─────┘ └─┘
typ  └─────┘ └─┘
2901  
2902  lemma pi.cons_ne {m : multiset α} {a a' : α} {b : δ a} {f : Πa∈m, δ a} (h' : a' ∈ a :: m) (h : a' ≠ a) :
id                         └──────┘                                       └┘   └┘        └┘  
src                        └──────┘                                                     └┘            
typ                        └──────┘                                       └┘   └┘        └┘  
doc                        └──────┘                                                      └┘
2903    pi.cons m a b f a' h' = f a' ((mem_cons.1 h').resolve_left h) :=
id     └─────┘     └┘ └┘   └┘   └──────┘  └┘ └──────────┘  
src    └─────┘                       └──────┘     └──────────┘
typ    └─────┘     └┘ └┘   └┘   └──────┘  └┘ └──────────┘  
2904  dif_neg h
id   └─────┘ 
src  └─────┘
typ  └─────┘ 
2905  
2906  lemma pi.cons_swap {a a' : α} {b : δ a} {b' : δ a'} {m : multiset α} {f : Πa∈m, δ a} (h : a ≠ a') :
id                                               └┘       └──────┘                      └┘
src                                                           └──────┘                           
typ                                              └┘       └──────┘                      └┘
doc                                                           └──────┘
2907    pi.cons (a' :: m) a b (pi.cons m a' b' f) == pi.cons (a :: m) a' b' (pi.cons m a b f) :=
id     └─────┘  └┘ └┘      └─────┘  └┘ └┘   └┘ └─────┘   └┘   └┘ └┘  └─────┘    
src    └─────┘     └┘         └─────┘            └┘ └─────┘    └┘           └─────┘
typ    └─────┘  └┘ └┘      └─────┘  └┘ └┘   └┘ └─────┘   └┘   └┘ └┘  └─────┘    
doc                └┘                                          └┘
2908  begin
st   └─────
2909    apply hfunext, { refl }, intros a'' _ h, subst h,
id           └─────┘                                  
src    └────┘└─────┘    └───┘   └────────────┘  └────┘
typ    └────┘└─────┘    └───┘   └────────────┘  └────┘
doc    └────┘           └───┘   └────────────┘  └────┘
txt    └────┘           └───┘   └────────────┘  └────┘
par    └────┘           └───┘   └────────────┘  └────┘
pid                                 └──────┘       
st   ──────────────┘└──┘└───┘└┘└─────────────┘└───────┘└─
2910    apply hfunext, { rw [cons_swap] }, intros ha₁ ha₂ h,
id           └─────┘        └───────┘
src    └────┘└─────┘    └──┘└───────┘└┘   └──────────────┘
typ    └────┘└─────┘    └──┘└───────┘└┘   └──────────────┘
doc    └────┘           └──┘         └┘   └──────────────┘
txt    └────┘           └──┘         └┘   └──────────────┘
par    └────┘           └──┘         └┘   └──────────────┘
pid                      └┘                  └────────┘
st   ──────────────┘└──┘└───────────┘└┘└───────────────┘└─
2911    by_cases h₁ : a'' = a; by_cases h₂ : a'' = a';
id                   └─┘                  └─┘   └┘
src    └───────┘  └─┘      └───────┘  └─┘    
typ    └───────┘  └─┘└─┘  └───────┘  └─┘└─┘ └┘
doc    └───────┘  └─┘       └───────┘  └─┘    
txt    └───────┘  └─┘       └───────┘  └─┘    
par    └───────┘  └─┘       └───────┘  └─┘    
pid              └─┘                 └─┘    
st   ─────────────────────────────────────────────────
2912      simp [*, pi.cons_same, pi.cons_ne] at *,
id                └──────────┘  └────────┘
src      └───────┘└──────────┘└┘└────────┘└────┘
typ      └───────┘└──────────┘└┘└────────┘└────┘
doc      └───────┘            └┘          └────┘
txt      └───────┘            └┘          └────┘
par      └───────┘            └┘          └────┘
pid          └──┘            └┘          └──┘
st   ──────────────────────────────────────────┘└─
2913    { subst h₁, rw [pi.cons_same, pi.cons_same] },
id             └┘      └──────────┘  └──────────┘
src      └────┘    └──┘└──────────┘└┘└──────────┘└┘
typ      └────┘└┘  └──┘└──────────┘└┘└──────────┘└┘
doc      └────┘    └──┘            └┘            └┘
txt      └────┘    └──┘            └┘            └┘
par      └────┘    └──┘            └┘            └┘
pid                 └┘            └┘            
st   ───┘└──────┘└────────────────┘└────────────┘└┘
2914    { subst h₂, rw [pi.cons_same, pi.cons_same] }
id             └┘      └──────────┘  └──────────┘
src      └────┘    └──┘└──────────┘└┘└──────────┘└┘
typ      └────┘└┘  └──┘└──────────┘└┘└──────────┘└┘
doc      └────┘    └──┘            └┘            └┘
txt      └────┘    └──┘            └┘            └┘
par      └────┘    └──┘            └┘            └┘
pid                 └┘            └┘            
st   ───────────┘└────────────────┘└────────────┘└─
2915  end
st   ──┘
2916  
2917  /-- `pi m t` constructs the Cartesian product over `t` indexed by `m`. -/
2918  def pi (m : multiset α) (t : Πa, multiset (δ a)) : multiset (Πa∈m, δ a) :=
id               └──────┘           └──────┘        └──────┘       
src              └──────┘             └──────┘          └──────┘
typ              └──────┘           └──────┘        └──────┘       
doc              └──────┘             └──────┘          └──────┘
2919  m.rec_on {pi.empty δ} (λa m (p : multiset (Πa∈m, δ a)), (t a).bind $ λb, p.map $ pi.cons m a b)
id   └─────┘ └──────┘            └──────┘              └──┘       └──┘   └─────┘   
src   └─────┘ └──────┘               └──────┘                    └──┘         └──┘   └─────┘
typ  └─────┘ └──────┘            └──────┘              └──┘       └──┘   └─────┘   
doc                                   └──────┘                    └──┘         └──┘
2920  begin
st   └─────
2921    intros a a' m n,
src    └─────────────┘
typ    └─────────────┘
doc    └─────────────┘
txt    └─────────────┘
par    └─────────────┘
pid          └───────┘
st   ────────────────┘└─
2922    by_cases eq : a = a',
id                     └┘
src    └───────┘  └─┘ 
typ    └───────┘  └─┘└┘
doc    └───────┘  └─┘  
txt    └───────┘  └─┘  
par    └───────┘  └─┘  
pid              └─┘  
st   ─────────────────────┘└─
2923    { subst eq },
id             └┘
src      └────┘└┘
typ      └────┘└┘
doc      └────┘  
txt      └────┘  
par      └────┘  
pid             
st   ───┘└───────┘└┘
2924    { simp [map_bind, bind_bind (t a') (t a)],
id             └──────┘  └───────┘    └┘    
src      └────┘└──────┘└┘└───────┘    └┘   └┘
typ      └────┘└──────┘└┘└───────┘  └┘└┘ └┘
doc      └────┘        └┘             └┘   └┘
txt      └────┘        └┘             └┘   └┘
par      └────┘        └┘             └┘   └┘
pid                  └┘             └┘   └┘
st   ──────────────────────────────────────────┘└─
2925      apply bind_hcongr, { rw [cons_swap a a'] },
id             └─────────┘        └───────┘  └┘
src      └────┘└─────────┘    └──┘└───────┘   └┘
typ      └────┘└─────────┘    └──┘└───────┘└┘└┘
doc      └────┘               └──┘            └┘
txt      └────┘               └──┘            └┘
par      └────┘               └──┘            └┘
pid                            └┘            
st   ────────────────────┘└──┘└────────────────┘└┘
2926      intros b hb,
src      └─────────┘
typ      └─────────┘
doc      └─────────┘
txt      └─────────┘
par      └─────────┘
pid            └───┘
st   ──────────────┘└─
2927      apply bind_hcongr, { rw [cons_swap a a'] },
id             └─────────┘        └───────┘  └┘
src      └────┘└─────────┘    └──┘└───────┘   └┘
typ      └────┘└─────────┘    └──┘└───────┘└┘└┘
doc      └────┘               └──┘            └┘
txt      └────┘               └──┘            └┘
par      └────┘               └──┘            └┘
pid                            └┘            
st   ────────────────────┘└──┘└────────────────┘└┘
2928      intros b' hb',
src      └───────────┘
typ      └───────────┘
doc      └───────────┘
txt      └───────────┘
par      └───────────┘
pid            └─────┘
st   ────────────────┘└─
2929      apply map_hcongr, { rw [cons_swap a a'] },
id             └────────┘        └───────┘  └┘
src      └────┘└────────┘    └──┘└───────┘   └┘
typ      └────┘└────────┘    └──┘└───────┘└┘└┘
doc      └────┘              └──┘            └┘
txt      └────┘              └──┘            └┘
par      └────┘              └──┘            └┘
pid                           └┘            
st   ───────────────────┘└──┘└────────────────┘└┘
2930      intros f hf,
src      └─────────┘
typ      └─────────┘
doc      └─────────┘
txt      └─────────┘
par      └─────────┘
pid            └───┘
st   ──────────────┘└─
2931      exact pi.cons_swap eq }
id             └──────────┘ └┘
src      └────┘└──────────┘└┘
typ      └────┘└──────────┘└┘
doc      └────┘              
txt      └────┘              
par      └────┘              
pid                         
st   ─────────────────────────┘└─
2932  end
st   ──┘
2933  
2934  @[simp] lemma pi_zero (t : Πa, multiset (δ a)) : pi 0 t = pi.empty δ :: 0 := rfl
id                                 └──────┘        └┘     └──────┘  └┘      └─┘
src                                 └──────┘          └┘      └──────┘   └┘      └─┘
typ                                └──────┘        └┘     └──────┘  └┘      └─┘
doc    └──┘                         └──────┘          └┘                  └┘
2935  
2936  @[simp] lemma pi_cons (m : multiset α) (t : Πa, multiset (δ a)) (a : α) :
id                              └──────┘           └──────┘           
src                             └──────┘             └──────┘
typ                             └──────┘           └──────┘           
doc    └──┘                     └──────┘             └──────┘
2937    pi (a :: m) t = ((t a).bind $ λb, (pi m t).map $ pi.cons m a b) :=
id     └┘   └┘         └──┘        └┘   └─┘    └─────┘   
src    └┘    └┘             └──┘         └┘     └─┘    └─────┘
typ    └┘   └┘         └──┘        └┘   └─┘    └─────┘   
doc    └┘    └┘              └──┘         └┘     └─┘
2938  rec_on_cons a m
id   └─────────┘  
src  └─────────┘
typ  └─────────┘  
2939  
2940  lemma injective_pi_cons {a : α} {b : δ a} {s : multiset α} (hs : a ∉ s) :
id                                               └──────┘           
src                                                 └──────┘            
typ                                              └──────┘           
doc                                                 └──────┘
2941    function.injective (pi.cons s a b) :=
id     └────────────────┘  └─────┘   
src    └────────────────┘  └─────┘
typ    └────────────────┘  └─────┘   
2942  assume f₁ f₂ eq, funext $ assume a', funext $ assume h',
id          └┘ └┘ └┘  └────┘          └┘  └────┘          └┘
src               └┘  └────┘              └────┘
typ         └┘ └┘ └┘  └────┘          └┘  └────┘          └┘
2943  have ne : a ≠ a', from assume h, hs $ h.symm ▸ h',
id               └┘                └┘   └───┘  └┘
src                                        └───┘ 
typ              └┘                └┘   └───┘  └┘
2944  have a' ∈ a :: s, from mem_cons_of_mem h',
id        └┘   └┘        └─────────────┘ └┘
src             └┘         └─────────────┘
typ       └┘   └┘        └─────────────┘ └┘
doc              └┘
2945  calc f₁ a' h' = pi.cons s a b f₁ a' this : by rw [pi.cons_ne this ne.symm]
id        └┘ └┘ └┘   └─────┘    └┘ └┘ └──┘          └────────┘ └──┘ └─────┘
src                  └─────┘                       └──┘└────────┘    └─────┘└─
typ       └┘ └┘ └┘   └─────┘    └┘ └┘ └──┘      └──┘└────────┘└──┘└─────┘└─
doc                                                └──┘                     └─
txt                                                └──┘                     └─
par                                                └──┘                     └─
pid                                                  └┘                     
st                                                └──────────────────────────┘
2946    ... = pi.cons s a b f₂ a' this : by rw [eq]
id           └─────┘    └┘ └┘ └──┘          └┘
src  ─┘      └─────┘                       └──┘└┘└─
typ  ─┘      └─────┘    └┘ └┘ └──┘      └──┘└┘└─
doc  ─┘                                    └──┘  └─
txt  ─┘                                    └──┘  └─
par  ─┘                                    └──┘  └─
pid  ─┘                                      └┘  
st   ─┘                                   └─────┘
2947    ... = f₂ a' h' : by rw [pi.cons_ne this ne.symm]
id           └┘ └┘ └┘          └────────┘ └──┘ └─────┘
src  ─┘                    └──┘└────────┘    └─────┘└─
typ  ─┘      └┘ └┘ └┘      └──┘└────────┘└──┘└─────┘└─
doc  ─┘                    └──┘                     └─
txt  ─┘                    └──┘                     └─
par  ─┘                    └──┘                     └─
pid  ─┘                      └┘                     
st   ─┘                   └──────────────────────────┘
2948  
src  
typ  
doc  
txt  
par  
pid  
st   
2949  lemma card_pi (m : multiset α) (t : Πa, multiset (δ a)) :
id                      └──────┘           └──────┘   
src                     └──────┘             └──────┘
typ                     └──────┘           └──────┘   
doc                     └──────┘             └──────┘
2950    card (pi m t) = prod (m.map $ λa, card (t a)) :=
id     └──┘  └┘     └──┘  └──┘      └──┘   
src    └──┘  └┘       └──┘   └──┘       └──┘
typ    └──┘  └┘     └──┘  └──┘      └──┘   
doc    └──┘  └┘        └──┘   └──┘       └──┘
2951  multiset.induction_on m (by simp) (by simp [mul_comm] {contextual := tt})
id   └───────────────────┘                      └──────┘                 └┘
src  └───────────────────┘       └──┘      └────┘└──────┘└┘ └────────────┘└┘
typ  └───────────────────┘      └──┘      └────┘└──────┘└┘ └────────────┘└┘
doc                              └──┘      └────┘        └┘ └────────────┘  
txt                              └──┘      └────┘        └┘ └────────────┘  
par                              └──┘      └────┘        └┘ └────────────┘  
pid                                                     └────────────┘  
st                              └───┘     └─────────────────────────────────┘
2952  
2953  lemma nodup_pi {s : multiset α} {t : Πa, multiset (δ a)} :
id                       └──────┘           └──────┘   
src                      └──────┘             └──────┘
typ                      └──────┘           └──────┘   
doc                      └──────┘             └──────┘
2954    nodup s → (∀a∈s, nodup (t a)) → nodup (pi s t) :=
id     └───┘         └───┘        └───┘  └┘  
src    └───┘            └───┘          └───┘  └┘
typ    └───┘         └───┘        └───┘  └┘  
doc    └───┘            └───┘          └───┘  └┘
2955  multiset.induction_on s (assume _ _, nodup_singleton _)
id   └───────────────────┘             └─────────────┘
src  └───────────────────┘                └─────────────┘
typ  └───────────────────┘             └─────────────┘
2956  begin
st   └─────
2957    assume a s ih hs ht,
src    └─────────────────┘
typ    └─────────────────┘
doc    └─────────────────┘
txt    └─────────────────┘
par    └─────────────────┘
pid    └─────────────────┘
st   ────────────────────┘└─
2958    have has : a ∉ s, by simp at hs; exact hs.1,
id                                         └┘
src    └─────────┘       └────────┘  └────┘  └┘
typ    └─────────┘     └────────┘  └────┘└┘└┘
doc    └─────────┘        └────────┘  └────┘  └┘
txt    └─────────┘        └────────┘  └────┘  └┘
par    └─────────┘        └────────┘  └────┘  └┘
pid    └──────┘└─┘            └───┘         └┘
st   ─────────────────┘                           └─
2959    have hs : nodup s, by simp at hs; exact hs.2,
id               └───┘                        └┘
src    └────────┘└───┘      └────────┘  └────┘  └┘
typ    └────────┘└───┘     └────────┘  └────┘└┘└┘
doc    └────────┘└───┘      └────────┘  └────┘  └┘
txt    └────────┘           └────────┘  └────┘  └┘
par    └────────┘           └────────┘  └────┘  └┘
pid    └─────┘└─┘               └───┘         └┘
st   ──────────────────┘                           └─
2960    simp,
src    └──┘
typ    └──┘
doc    └──┘
txt    └──┘
par    └──┘
st   ─────┘└─
2961    split,
src    └───┘
typ    └───┘
doc    └───┘
txt    └───┘
par    └───┘
st   ──────┘└─
2962    { assume b hb,
src      └─────────┘
typ      └─────────┘
doc      └─────────┘
txt      └─────────┘
par      └─────────┘
pid      └─────────┘
st   ───┘└─────────┘└─
2963      from nodup_map (injective_pi_cons has) (ih hs $ assume a' h', ht a' $ mem_cons_of_mem h') },
id            └───────┘  └───────────────┘ └─┘   └┘ └┘                 └┘      └─────────────┘
src      └───┘└───────┘ └───────────────┘   └┘            └──────┘     └─────────────┘  └┘
typ      └───┘└───────┘ └───────────────┘└─┘└┘ └┘└┘       └──────┘└┘   └─────────────┘  └┘
doc      └───┘                              └┘            └──────┘                      └┘
txt      └───┘                              └┘            └──────┘                      └┘
par      └───┘                              └┘            └──────┘                      └┘
pid      └───┘                              └┘            └──────┘                      
st   ─────────────────────────────────────────────────────────────────────────────────────────────┘└┘
2964    { apply pairwise_of_nodup _ (ht a $ mem_cons_self _ _),
id             └───────────────┘    └┘    └───────────┘
src      └────┘└───────────────┘└─┘     └───────────┘└───┘
typ      └────┘└───────────────┘└─┘ └┘ └───────────┘└───┘
doc      └────┘                 └─┘                  └───┘
txt      └────┘                 └─┘                  └───┘
par      └────┘                 └─┘                  └───┘
pid                            └─┘                  └───┘
st   ───────────────────────────────────────────────────────┘└─
2965      from assume b₁ hb₁ b₂ hb₂ neb, disjoint_map_map.2 (assume f hf g hg eq,
id                                      └──────────────┘
src      └───┘      └──────────────────┘└──────────────┘└─┘       └──────────────
typ      └───┘      └──────────────────┘└──────────────┘└─┘       └──────────────
doc      └───┘      └──────────────────┘                └─┘       └──────────────
txt      └───┘      └──────────────────┘                └─┘       └──────────────
par      └───┘      └──────────────────┘                └─┘       └──────────────
pid      └───┘      └──────────────────┘                └─┘       └──────────────
st   ────────────────────────────────────────────────────────────────────────────
2966        have pi.cons s a b₁ f a (mem_cons_self _ _) = pi.cons s a b₂ g a (mem_cons_self _ _),
id                                                      └─────┘           └───────────┘
src  ─────┘    └───────┘                    └────┘└─────┘       └───────────┘└──────
typ  ─────┘    └───────┘                    └────┘└─────┘     └───────────┘└──────
doc  ─────┘    └───────┘                    └────┘                            └──────
txt  ─────┘    └───────┘                    └────┘                            └──────
par  ─────┘    └───────┘                    └────┘                            └──────
pid  ─────┘    └───────┘                    └────┘                            └──────
st   ────────────────────────────────────────────────────────────────────────────────────────────
2967          by rw [eq],
id                  └┘
src  ──────────┘└──┘└┘└─
typ  ──────────┘└──┘└┘└─
doc  ──────────┘└──┘  └─
txt  ──────────┘└──┘  └─
par  ──────────┘└──┘  └─
pid  ──────────────┘  └──
st   ─────────┘└─────┘└─
2968        neb $ show b₁ = b₂, by rwa [pi.cons_same, pi.cons_same] at this) }
id                                    └──────────┘  └──────────┘
src  ─────┘             └───┘└───┘└──────────┘└┘└──────────┘└───────┘└┘
typ  ─────┘            └───┘└───┘└──────────┘└┘└──────────┘└───────┘└┘
doc  ─────┘             └───┘└───┘            └┘            └───────┘└┘
txt  ─────┘             └───┘└───┘            └┘            └───────┘└┘
par  ─────┘             └───┘└───┘            └┘            └───────┘└┘
pid  ─────┘             └────────┘            └┘            └────────┘
st   ───────────────────────────┘└────────────────┘└────────────┘└──────┘└┘└─
2969  end
st   ──┘
2970  
2971  lemma mem_pi (m : multiset α) (t : Πa, multiset (δ a)) :
id                     └──────┘           └──────┘   
src                    └──────┘             └──────┘
typ                    └──────┘           └──────┘   
doc                    └──────┘             └──────┘
2972    ∀f:Πa∈m, δ a, (f ∈ pi m t) ↔ (∀a (h : a ∈ m), f a h ∈ t a) :=
id                  └┘                       
src                      └┘                             
typ                 └┘                       
doc                       └┘
2973  begin
st   └─────
2974    refine multiset.induction_on m (λ f, _) (λ a m ih f, _),
id            └───────────────────┘ 
src    └─────┘└───────────────────┘   └─────┘  └───────────┘
typ    └─────┘└───────────────────┘  └─────┘  └───────────┘
doc    └─────┘                        └─────┘  └───────────┘
txt    └─────┘                        └─────┘  └───────────┘
par    └─────┘                        └─────┘  └───────────┘
pid                                  └─────┘  └───────────┘
st   ────────────────────────────────────────────────────────┘└─
2975    { simpa using show f = pi.empty δ, by funext a ha; exact ha.elim },
id                          └──────┘                         └─────┘
src      └──────────┘     └──────┘ └───┘└─────────┘└┘└────┘└─────┘
typ      └──────────┘    └──────┘└───┘└─────────┘└┘└────┘└─────┘
doc      └──────────┘               └───┘└─────────┘└┘└────┘       
txt      └──────────┘               └───┘└─────────┘└┘└────┘       
par      └──────────┘               └───┘└─────────┘└┘└────┘       
pid           └────┘               └──────────────────────┘       
st   ───┘└─────────────────────────────────┘└──────────────────────────┘└┘
2976    simp, split,
src    └──┘  └───┘
typ    └──┘  └───┘
doc    └──┘  └───┘
txt    └──┘  └───┘
par    └──┘  └───┘
st   ─────┘└─────┘└─
2977    { rintro ⟨b, hb, f', hf', rfl⟩ a' ha',
src      └─────────────────────────────────┘
typ      └─────────────────────────────────┘
doc      └─────────────────────────────────┘
txt      └─────────────────────────────────┘
par      └─────────────────────────────────┘
pid            └───────────────────────────┘
st   ───┘└─────────────────────────────────┘└─
2978      rw [ih] at hf',
id           └┘
src      └──┘  └──────┘
typ      └──┘└┘└──────┘
doc      └──┘  └──────┘
txt      └──┘  └──────┘
par      └──┘  └──────┘
pid        └┘  └─────┘
st   ─────────┘└─────┘└─
2979      by_cases a' = a,
id                └┘   
src      └───────┘   
typ      └───────┘└┘ 
doc      └───────┘   
txt      └───────┘   
par      └───────┘   
pid                 
st   ──────────────────┘└─
2980      { subst h, rwa [pi.cons_same] },
id                      └──────────┘
src        └────┘   └───┘└──────────┘└┘
typ        └────┘  └───┘└──────────┘└┘
doc        └────┘   └───┘            └┘
txt        └────┘   └───┘            └┘
par        └────┘   └───┘            └┘
pid                   └┘            
st   ─────┘└─────┘└─────────────────┘└┘
2981      { rw [pi.cons_ne _ h], apply hf' } },
id             └────────┘   
src        └──┘└────────┘└─┘   └────┘   
typ        └──┘└────────┘└─┘  └────┘   
doc        └──┘          └─┘   └────┘   
txt        └──┘          └─┘   └────┘   
par        └──┘          └─┘   └────┘   
pid          └┘          └─┘           
st   ───────────────────────┘└───────────┘└──┘
2982    { intro hf,
src      └──────┘
typ      └──────┘
doc      └──────┘
txt      └──────┘
par      └──────┘
pid           └─┘
st   ───────────┘└─
2983      refine ⟨_, hf a (mem_cons_self a _), λa ha, f a (mem_cons_of_mem ha),
id                        └───────────┘                 └─────────────┘
src      └─────┘ └─┘    └───────────┘ └───┘ └────┘   └─────────────┘  └──
typ      └─────┘ └─┘    └───────────┘└───┘ └────┘  └─────────────┘  └──
doc      └─────┘ └─┘                  └───┘ └────┘                    └──
txt      └─────┘ └─┘                  └───┘ └────┘                    └──
par      └─────┘ └─┘                  └───┘ └────┘                    └──
pid             └─┘                  └───┘ └────┘                    └──
st   ──────────────────────────────────────────────────────────────────────────
2984        (ih _).2 (λ a' h', hf _ _), _⟩,
id          └┘                └┘
src  ─────┘   └────┘  └──────┘  └───────┘
typ  ─────┘ └┘└────┘  └──────┘└┘└───────┘
doc  ─────┘   └────┘  └──────┘  └───────┘
txt  ─────┘   └────┘  └──────┘  └───────┘
par  ─────┘   └────┘  └──────┘  └───────┘
pid  ─────┘   └────┘  └──────┘  └───────┘
st   ───────────────────────────────────┘└─
2985      funext a' h',
src      └──────────┘
typ      └──────────┘
doc      └──────────┘
txt      └──────────┘
par      └──────────┘
pid            └────┘
st   ───────────────┘└─
2986      by_cases a' = a,
id                └┘   
src      └───────┘   
typ      └───────┘└┘ 
doc      └───────┘   
txt      └───────┘   
par      └───────┘   
pid                 
st   ──────────────────┘└─
2987      { subst h, rw [pi.cons_same] },
id                     └──────────┘
src        └────┘   └──┘└──────────┘└┘
typ        └────┘  └──┘└──────────┘└┘
doc        └────┘   └──┘            └┘
txt        └────┘   └──┘            └┘
par        └────┘   └──┘            └┘
pid                  └┘            
st   ─────┘└─────┘└────────────────┘└┘
2988      { rw [pi.cons_ne _ h] } }
id             └────────┘   
src        └──┘└────────┘└─┘ └┘
typ        └──┘└────────┘└─┘└┘
doc        └──┘          └─┘ └┘
txt        └──┘          └─┘ └┘
par        └──┘          └─┘ └┘
pid          └┘          └─┘ 
st   ───────────────────────┘└───
2989  end
st   ──┘
2990  
2991  end pi
2992  end multiset
2993  
2994  namespace multiset
2995  
2996  instance : functor multiset :=
id              └─────┘ └──────┘
src             └─────┘ └──────┘
typ             └─────┘ └──────┘
doc                     └──────┘
2997  { map := @map }
id             └─┘
src            └─┘
typ            └─┘
doc            └─┘
2998  
2999  instance : is_lawful_functor multiset :=
id              └───────────────┘ └──────┘
src             └───────────────┘ └──────┘
typ             └───────────────┘ └──────┘
doc                               └──────┘
3000  by refine { .. }; intros; simp
id             
src     └─────┘└───┘  └────┘  └────
typ     └─────┘└───┘  └────┘  └────
doc     └─────┘ └───┘  └────┘  └────
txt     └─────┘ └───┘  └────┘  └────
par     └─────┘ └───┘  └────┘  └────
pid            └───┘              
st     └────────────────────────────
3001  
src  
typ  
doc  
txt  
par  
pid  
st   
3002  open is_lawful_traversable is_comm_applicative
3003  
3004  variables {F : Type u_1 → Type u_1} [applicative F] [is_comm_applicative F]
id                  └──┘                  └─────────┘     └─────────────────┘
src                                       └─────────┘     └─────────────────┘
typ                 └──┘                  └─────────┘     └─────────────────┘
3005  variables {α' β' : Type u_1} (f : α' → F β')
3006  
3007  def traverse : multiset α' → F (multiset β') :=
id                  └──────┘ └┘     └──────┘ └┘
src                 └──────┘         └──────┘
typ                 └──────┘ └┘     └──────┘ └┘
doc                 └──────┘         └──────┘
3008  quotient.lift (functor.map coe ∘ traversable.traverse f)
id   └───────────┘  └─────────┘ └─┘  └──────────────────┘ 
src  └───────────┘  └─────────┘ └─┘  └──────────────────┘
typ  └───────────┘  └─────────┘ └─┘  └──────────────────┘ 
3009  begin
st   └─────
3010    introv p, unfold function.comp,
src    └──────┘  └──────────────────┘
typ    └──────┘  └──────────────────┘
doc    └──────┘  └──────────────────┘
txt    └──────┘  └──────────────────┘
par    └──────┘  └──────────────────┘
pid          └┘        └────────────┘
st   ─────────┘└────────────────────┘└─
3011    induction p,
id               
src    └────────┘
typ    └────────┘
doc    └────────┘
txt    └────────┘
par    └────────┘
pid             
st   ────────────┘└─
3012    case perm.nil { refl },
src    └──────────────┘└───┘
typ    └──────────────┘└───┘
doc    └──────────────┘└───┘
txt    └──────────────┘└───┘
par    └──────────────┘└───┘
pid        └───────┘└──────┘
st   ────────────────┘└────┘└┘
3013    case perm.skip {
src    └────────────────
typ    └────────────────
doc    └────────────────
txt    └────────────────
par    └────────────────
pid        └────────┘└─
st   ─────────────────┘
3014      have : multiset.cons <$> f p_x <*> (coe <$> traverse f p_l₁) =
id                            └─┘       └─┘                     └──┘  
src  ───┘└─────┘             └─┘    └─┘                    └┘
typ  ───┘└─────┘             └─┘    └─┘                └──┘└┘
doc  ───┘└─────┘                                           └┘ 
txt  ───┘└─────┘                                           └┘ 
par  ───┘└─────┘                                           └┘ 
pid  ──────────┘                                           └┘ 
st   ───────────────────────────────────────────────────────────────────
3015        multiset.cons <$> f p_x <*> (coe <$> traverse f p_l₂),
id         └───────────┘       └─┘      └─┘     └──────┘  └──┘
src  ─────┘└───────────┘           └─┘   └──────┘     └─
typ  ─────┘└───────────┘    └─┘    └─┘   └──────┘└──┘└─
doc  ─────┘└───────────┘                              └─
txt  ─────┘                                           └─
par  ─────┘                                           └─
pid  ─────┘                                           └──
st   ──────────────────────────────────────────────────────────┘└─
3016      { rw [p_ih] },
id             └──┘
src  ─────┘└──┘    └┘└──
typ  ─────┘└──┘└──┘└┘└──
doc  ─────┘└──┘    └┘└──
txt  ─────┘└──┘    └┘└──
par  ─────┘└──┘    └┘└──
pid  ─────────┘    └────
st   ────┘└───────┘└─
3017      simpa with functor_norm },
src  ───┘└──────────────────────┘
typ  ───┘└──────────────────────┘
doc  ───┘└──────────────────────┘
txt  ───┘└──────────────────────┘
par  ───┘└──────────────────────┘
pid  ────────────────────────────┘
st   ───────────────────────────┘└┘
3018    case perm.swap {
src    └────────────────
typ    └────────────────
doc    └────────────────
txt    └────────────────
par    └────────────────
pid        └────────┘└─
st   ─────────────────┘
3019      have : (λa b (l:list β'), (↑(a :: b :: l) : multiset β')) <$> f p_y <*> f p_x =
id                       └──┘                        └──────┘ └┘
src  ───┘└─────┘  └─────┘└──┘  └─┘          └──┘└──────┘  └─┘               
typ  ───┘└─────┘  └─────┘└──┘  └─┘          └──┘└──────┘└┘└─┘               
doc  ───┘└─────┘  └─────┘      └─┘          └──┘└──────┘  └─┘               
txt  ───┘└─────┘  └─────┘      └─┘          └──┘          └─┘               
par  ───┘└─────┘  └─────┘      └─┘          └──┘          └─┘               
pid  ──────────┘  └─────┘      └─┘          └──┘          └─┘               
st   ────────────────────────────────────────────────────────────────────────────────────
3020        (λa b l, ↑(a :: b :: l)) <$> f p_x <*> f p_y,
id                                        └─┘      └─┘
src  ─────┘  └─────┘         └─┘              └─
typ  ─────┘  └─────┘         └─┘    └─┘   └─┘└─
doc  ─────┘  └─────┘         └─┘              └─
txt  ─────┘  └─────┘         └─┘              └─
par  ─────┘  └─────┘         └─┘              └─
pid  ─────┘  └─────┘         └─┘              └─
st   ─────────────────────────────────────────────────┘└─
3021      { rw [is_comm_applicative.commutative_map],
id             └─────────────────────────────────┘
src  ─────┘└──┘└─────────────────────────────────┘└─
typ  ─────┘└──┘└─────────────────────────────────┘└─
doc  ─────┘└──┘                                   └─
txt  ─────┘└──┘                                   └─
par  ─────┘└──┘                                   └─
pid  ─────────┘                                   └──
st   ────┘└──────────────────────────────────────┘└──
3022        congr, funext a b l, simpa [flip] using perm.swap b a l },
id                                     └──┘        └───────┘   
src  ─────┘└───┘└┘└──────────┘└┘└─────┘└──┘└──────┘└───────┘   └──
typ  ─────┘└───┘└┘└──────────┘└┘└─────┘└──┘└──────┘└───────┘└──
doc  ─────┘     └┘└──────────┘└┘└─────┘    └──────┘            └──
txt  ─────┘└───┘└┘└──────────┘└┘└─────┘    └──────┘            └──
par  ─────┘└───┘└┘└──────────┘└┘└─────┘    └──────┘            └──
pid  ─────────────────────────────────┘    └──────┘            └───
st   ──────────┘└────────────┘└───────────────────────────────────┘└─
3023      simp [(∘), this] with functor_norm },
id                 └──┘
src  ───┘└────┘└──┘    └──────────────────┘
typ  ───┘└────┘└──┘└──┘└──────────────────┘
doc  ───┘└────┘ └──┘    └──────────────────┘
txt  ───┘└────┘ └──┘    └──────────────────┘
par  ───┘└────┘ └──┘    └──────────────────┘
pid  ─────────┘ └──┘    └───────────────────┘
st   ──────────────────────────────────────┘└┘
3024    case perm.trans { simp [*] }
src    └────────────────┘└───────┘└┘
typ    └────────────────┘└───────┘└┘
doc    └────────────────┘└───────┘└┘
txt    └────────────────┘└───────┘└┘
par    └────────────────┘└───────┘└┘
pid        └─────────┘└──────────┘
st   ────────────────────────────┘
3025  end
st   └─┘
3026  
3027  instance : monad multiset :=
id              └───┘ └──────┘
src             └───┘ └──────┘
typ             └───┘ └──────┘
doc                   └──────┘
3028  { pure := λ α x, x::0,
id                  └┘
src                    └┘
typ                 └┘
doc                    └┘
3029    bind := @bind,
id              └──┘
src             └──┘
typ             └──┘
doc             └──┘
3030    .. multiset.functor }
id        └──────────────┘
src       └──────────────┘
typ       └──────────────┘
3031  
3032  instance : is_lawful_monad multiset :=
id              └─────────────┘ └──────┘
src             └─────────────┘ └──────┘
typ             └─────────────┘ └──────┘
doc                             └──────┘
3033  { bind_pure_comp_eq_map := λ α β f s, multiset.induction_on s rfl $ λ a s ih,
id                                    └───────────────────┘  └─┘       └┘
src                                       └───────────────────┘   └─┘
typ                                   └───────────────────┘  └─┘       └┘
3034      by rw [bind_cons, map_cons, bind_zero, add_zero],
id              └───────┘  └──────┘  └───────┘  └──────┘
src         └──┘└───────┘└┘└──────┘└┘└───────┘└┘└──────┘
typ         └──┘└───────┘└┘└──────┘└┘└───────┘└┘└──────┘
doc         └──┘         └┘        └┘         └┘        
txt         └──┘         └┘        └┘         └┘        
par         └──┘         └┘        └┘         └┘        
pid           └┘         └┘        └┘         └┘        
st         └────────────┘└────────┘└─────────┘└────────┘
3035    pure_bind := λ α β x f, by simp only [cons_bind, zero_bind, add_zero],
id                                       └───────┘  └───────┘  └──────┘
src                               └─────────┘└───────┘└┘└───────┘└┘└──────┘
typ                           └─────────┘└───────┘└┘└───────┘└┘└──────┘
doc                               └─────────┘         └┘         └┘        
txt                               └─────────┘         └┘         └┘        
par                               └─────────┘         └┘         └┘        
pid                                   └──┘└┘         └┘         └┘        
st                               └─────────────────────────────────────────┘
3036    bind_assoc := @bind_assoc }
id                    └────────┘
src                   └────────┘
typ                   └────────┘
3037  
3038  open functor
3039  open traversable is_lawful_traversable
3040  
3041  @[simp]
doc    └──┘
3042  lemma lift_beta {α β : Type*} (x : list α) (f : list α → β)
id                                      └──┘        └──┘    
src                                     └──┘         └──┘
typ                                     └──┘        └──┘    
3043    (h : ∀ a b : list α, a ≈ b → f a = f b) :
id                  └──┘            
src                 └──┘               
typ                 └──┘            
3044    quotient.lift f h (x : multiset α) = f x :=
id     └───────────┘       └──────┘     
src    └───────────┘          └──────┘    
typ    └───────────┘       └──────┘     
doc                           └──────┘
3045  quotient.lift_beta _ _ _
id   └────────────────┘
src  └────────────────┘
typ  └────────────────┘
3046  
3047  @[simp]
doc    └──┘
3048  lemma map_comp_coe {α β} (h : α → β) :
id                                    
typ                                   
3049    functor.map h ∘ coe = (coe ∘ functor.map h : list α → multiset β) :=
id     └─────────┘   └─┘   └─┘  └─────────┘    └──┘    └──────┘ 
src    └─────────┘    └─┘   └─┘  └─────────┘     └──┘     └──────┘
typ    └─────────┘   └─┘   └─┘  └─────────┘    └──┘    └──────┘ 
doc                                                          └──────┘
3050  by funext; simp [functor.map]
src     └────┘  └────┘           └─
typ     └────┘  └────┘           └─
doc     └────┘  └────┘           └─
txt     └────┘  └────┘           └─
par     └────┘  └────┘           └─
pid                            
st     └───────────────────────────
3051  
src  
typ  
doc  
txt  
par  
pid  
st   
3052  lemma id_traverse {α : Type*} (x : multiset α) :
id                                      └──────┘ 
src                                     └──────┘
typ                                     └──────┘ 
doc                                     └──────┘
3053    traverse id.mk x = x :=
id     └──────┘ └───┘   
src    └──────┘ └───┘   
typ    └──────┘ └───┘   
3054  quotient.induction_on x
id   └───────────────────┘ 
src  └───────────────────┘
typ  └───────────────────┘ 
3055  (by { intro, rw [traverse,quotient.lift_beta,function.comp],
id                    └──────┘ └────────────────┘ └───────────┘
src        └───┘  └──┘└──────┘└────────────────┘└───────────┘
typ        └───┘  └──┘└──────┘└────────────────┘└───────────┘
doc        └───┘  └──┘                                       
txt        └───┘  └──┘                                       
par        └───┘  └──┘                                       
pid                 └┘                                       
st      └──────┘└────────────┘└─────────────────┘└────────────┘└──
3056        simp, congr })
src        └──┘  └────┘
typ        └──┘  └────┘
doc        └──┘
txt        └──┘  └────┘
par        └──┘  └────┘
pid                   
st   ─────────┘└──────┘└┘
3057  
3058  lemma comp_traverse {G H : Type* → Type*}
id                              └───┘
typ                             └───┘
3059                 [applicative G] [applicative H]
id                   └─────────┘    └─────────┘ 
src                  └─────────┘     └─────────┘
typ                  └─────────┘    └─────────┘ 
3060                 [is_comm_applicative G] [is_comm_applicative H]
id                   └─────────────────┘    └─────────────────┘ 
src                  └─────────────────┘     └─────────────────┘
typ                  └─────────────────┘    └─────────────────┘ 
3061                 {α β γ : Type*}
3062                 (g : α → G β) (h : β → H γ) (x : multiset α) :
id                                             └──────┘ 
src                                                  └──────┘
typ                                            └──────┘ 
doc                                                  └──────┘
3063    traverse (comp.mk ∘ functor.map h ∘ g) x =
id     └──────┘  └─────┘  └─────────┘      
src    └──────┘  └─────┘  └─────────┘         
typ    └──────┘  └─────┘  └─────────┘      
3064    comp.mk (functor.map (traverse h) (traverse g x)) :=
id     └─────┘  └─────────┘  └──────┘    └──────┘  
src    └─────┘  └─────────┘  └──────┘     └──────┘
typ    └─────┘  └─────────┘  └──────┘    └──────┘  
3065  quotient.induction_on x
id   └───────────────────┘ 
src  └───────────────────┘
typ  └───────────────────┘ 
3066  (by intro;
src      └───┘
typ      └───┘
doc      └───┘
txt      └───┘
par      └───┘
st      └───────
3067      simp [traverse,comp_traverse] with functor_norm;
id             └──────┘ └───────────┘
src      └────┘└──────┘└───────────┘└─────────────────┘
typ      └────┘└──────┘└───────────┘└─────────────────┘
doc      └────┘                     └─────────────────┘
txt      └────┘                     └─────────────────┘
par      └────┘                     └─────────────────┘
pid                               └────────────────┘
st   ─────────────────────────────────────────────────────
3068      simp [(<$>),(∘)] with functor_norm)
id                   
src      └────┘ └───┘└───────────────────┘
typ      └────┘ └───┘└───────────────────┘
doc      └────┘ └───┘ └───────────────────┘
txt      └────┘ └───┘ └───────────────────┘
par      └────┘ └───┘ └───────────────────┘
pid           └───┘ └─┘└────────────────┘
st   ─────────────────────────────────────┘
3069  
3070  lemma map_traverse {G : Type* → Type*}
id                           └───┘
typ                          └───┘
3071                 [applicative G] [is_comm_applicative G]
id                   └─────────┘    └─────────────────┘ 
src                  └─────────┘     └─────────────────┘
typ                  └─────────┘    └─────────────────┘ 
3072                 {α β γ : Type*}
3073                 (g : α → G β) (h : β → γ)
id                                     
typ                                    
3074                 (x : multiset α) :
id                       └──────┘ 
src                      └──────┘
typ                      └──────┘ 
doc                      └──────┘
3075    functor.map (functor.map h) (traverse g x) =
id     └─────────┘  └─────────┘    └──────┘    
src    └─────────┘  └─────────┘     └──────┘      
typ    └─────────┘  └─────────┘    └──────┘    
3076    traverse (functor.map h ∘ g) x :=
id     └──────┘  └─────────┘     
src    └──────┘  └─────────┘   
typ    └──────┘  └─────────┘     
3077  quotient.induction_on x
id   └───────────────────┘ 
src  └───────────────────┘
typ  └───────────────────┘ 
3078  (by intro; simp [traverse] with functor_norm;
id                    └──────┘
src      └───┘  └────┘└──────┘└─────────────────┘
typ      └───┘  └────┘└──────┘└─────────────────┘
doc      └───┘  └────┘        └─────────────────┘
txt      └───┘  └────┘        └─────────────────┘
par      └───┘  └────┘        └─────────────────┘
pid                         └────────────────┘
st      └──────────────────────────────────────────
3079      rw [comp_map,map_traverse])
id           └──────┘ └──────────┘
src      └──┘└──────┘└──────────┘
typ      └──┘└──────┘└──────────┘
doc      └──┘                    
txt      └──┘                    
par      └──┘                    
pid        └┘                    
st   ───────┘└──────┘└───────────┘
3080  
3081  lemma traverse_map {G : Type* → Type*}
id                           └───┘
typ                          └───┘
3082                 [applicative G] [is_comm_applicative G]
id                   └─────────┘    └─────────────────┘ 
src                  └─────────┘     └─────────────────┘
typ                  └─────────┘    └─────────────────┘ 
3083                 {α β γ : Type*}
3084                 (g : α → β) (h : β → G γ)
id                                     
typ                                    
3085                 (x : multiset α) :
id                       └──────┘ 
src                      └──────┘
typ                      └──────┘ 
doc                      └──────┘
3086    traverse h (map g x) =
id     └──────┘   └─┘    
src    └──────┘    └─┘      
typ    └──────┘   └─┘    
doc                └─┘
3087    traverse (h ∘ g) x :=
id     └──────┘      
src    └──────┘    
typ    └──────┘      
3088  quotient.induction_on x
id   └───────────────────┘ 
src  └───────────────────┘
typ  └───────────────────┘ 
3089  (by intro; simp [traverse];
id                    └──────┘
src      └───┘  └────┘└──────┘
typ      └───┘  └────┘└──────┘
doc      └───┘  └────┘        
txt      └───┘  └────┘        
par      └───┘  └────┘        
pid                         
st      └────────────────────────
3090      rw [← traversable.traverse_map h g];
id             └──────────────────────┘  
src      └────┘└──────────────────────┘  
typ      └────┘└──────────────────────┘
doc      └────┘                          
txt      └────┘                          
par      └────┘                          
pid        └──┘                          
st   ───────┘└────────────────────────────┘└─
3091      [ refl, apply_instance ])
id       
src       └──┘  └─────────────┘
typ       └──┘  └─────────────┘
doc        └──┘  └─────────────┘
txt        └──┘  └─────────────┘
par        └──┘  └─────────────┘
pid                            
st   ───────────────────────────┘
3092  
3093  lemma naturality {G H : Type* → Type*}
id                           └───┘
typ                          └───┘
3094                  [applicative G] [applicative H]
id                    └─────────┘    └─────────┘ 
src                   └─────────┘     └─────────┘
typ                   └─────────┘    └─────────┘ 
3095                  [is_comm_applicative G] [is_comm_applicative H]
id                    └─────────────────┘    └─────────────────┘ 
src                   └─────────────────┘     └─────────────────┘
typ                   └─────────────────┘    └─────────────────┘ 
3096                  (eta : applicative_transformation G H)
id                          └────────────────────────┘  
src                         └────────────────────────┘
typ                         └────────────────────────┘  
3097                  {α β : Type*} (f : α → G β) (x : multiset α) :
id                                                 └──────┘ 
src                                                   └──────┘
typ                                                └──────┘ 
doc                                                   └──────┘
3098    eta (traverse f x) = traverse (@eta _ ∘ f) x :=
id     └─┘  └──────┘     └──────┘   └─┘      
src         └──────┘       └──────┘         
typ    └─┘  └──────┘     └──────┘   └─┘      
3099  quotient.induction_on x
id   └───────────────────┘ 
src  └───────────────────┘
typ  └───────────────────┘ 
3100  (by intro; simp [traverse,is_lawful_traversable.naturality] with functor_norm)
id                    └──────┘ └──────────────────────────────┘
src      └───┘  └────┘└──────┘└──────────────────────────────┘└─────────────────┘
typ      └───┘  └────┘└──────┘└──────────────────────────────┘└─────────────────┘
doc      └───┘  └────┘                                        └─────────────────┘
txt      └───┘  └────┘                                        └─────────────────┘
par      └───┘  └────┘                                        └─────────────────┘
pid                                                         └────────────────┘
st      └────────────────────────────────────────────────────────────────────────┘
3101  
3102  section choose
3103  variables (p : α → Prop) [decidable_pred p] (l : multiset α)
id                             └────────────┘         └──────┘
src                            └────────────┘         └──────┘
typ                            └────────────┘         └──────┘
doc                                                   └──────┘
3104  
3105  def choose_x : Π hp : (∃! a, a ∈ l ∧ p a), { a // a ∈ l ∧ p a } :=
id                          └┘                    
src                         └┘                          
typ                         └┘                    
3106  quotient.rec_on l (λ l' ex_unique, list.choose_x p l' (exists_of_exists_unique ex_unique)) begin
id   └─────────────┘     └┘ └───────┘  └───────────┘  └┘  └─────────────────────┘ └───────┘
src  └─────────────┘                    └───────────┘       └─────────────────────┘
typ  └─────────────┘     └┘ └───────┘  └───────────┘  └┘  └─────────────────────┘ └───────┘
st                                                                                              └─────
3107    intros,
src    └────┘
typ    └────┘
doc    └────┘
txt    └────┘
par    └────┘
st   ───────┘└─
3108    funext hp,
src    └───────┘
typ    └───────┘
doc    └───────┘
txt    └───────┘
par    └───────┘
pid          └─┘
st   ──────────┘└─
3109    suffices all_equal : ∀ x y : { t // t ∈ b ∧ p t }, x = y,
id                                                      
src    └───────────────────┘ └─────┘└────┘     └┘  
typ    └───────────────────┘ └─────┘└────┘   └┘  
doc    └───────────────────┘ └─────┘ └────┘      └┘   
txt    └───────────────────┘ └─────┘ └────┘      └┘   
par    └───────────────────┘ └─────┘ └────┘      └┘   
pid    └────────────────┘└─┘ └─────┘ └────┘      └┘   
st   ─────────────────────────────────────────────────────────┘└─
3110    { apply all_equal },
src      └────┘         
typ      └────┘         
doc      └────┘         
txt      └────┘         
par      └────┘         
pid                    
st   ───┘└──────────────┘└┘
3111    { rintros ⟨x, px⟩ ⟨y, py⟩,
src      └─────────────────────┘
typ      └─────────────────────┘
doc      └─────────────────────┘
txt      └─────────────────────┘
par      └─────────────────────┘
pid             └──────────────┘
st   ──────────────────────────┘└─
3112      rcases hp with ⟨z, ⟨z_mem_l, pz⟩, z_unique⟩,
id              └┘
src      └─────┘  └────────────────────────────────┘
typ      └─────┘└┘└────────────────────────────────┘
doc      └─────┘  └────────────────────────────────┘
txt      └─────┘  └────────────────────────────────┘
par      └─────┘  └────────────────────────────────┘
pid              └────────────────────────────────┘
st   ──────────────────────────────────────────────┘└─
3113      congr,
src      └───┘
typ      └───┘
txt      └───┘
par      └───┘
st   ────────┘└─
3114      calc x = z : z_unique x px
id       └──┘                  └┘
src      └──┘
typ      └──┘                  └┘
doc      └──┘
st   ───────────────────────────────
3115      ...    = y : (z_unique y py).symm }
id                     └──────┘  └┘ └──┘
src                                  └──┘
typ                    └──────┘  └┘ └──┘
st   ───────────────────────────────────┘└───
3116  end
st   ──┘
3117  
3118  def choose (hp : ∃! a, a ∈ l ∧ p a) : α := choose_x p l hp
id                    └┘               └──────┘   └┘
src                   └┘                     └──────┘
typ                   └┘               └──────┘   └┘
3119  
3120  lemma choose_spec (hp : ∃! a, a ∈ l ∧ p a) : choose p l hp ∈ l ∧ p (choose p l hp) :=
id                           └┘           └────┘   └┘      └────┘   └┘
src                          └┘                └────┘               └────┘
typ                          └┘           └────┘   └┘      └────┘   └┘
3121  (choose_x p l hp).property
id    └──────┘   └┘ └──────┘
src   └──────┘        └──────┘
typ   └──────┘   └┘ └──────┘
3122  
3123  lemma choose_mem (hp : ∃! a, a ∈ l ∧ p a) : choose p l hp ∈ l := (choose_spec _ _ _).1
id                          └┘           └────┘   └┘       └─────────┘       
src                         └┘                └────┘               └─────────┘       
typ                         └┘           └────┘   └┘       └─────────┘       
3124  
3125  lemma choose_property (hp : ∃! a, a ∈ l ∧ p a) : p (choose p l hp) := (choose_spec _ _ _).2
id                               └┘             └────┘   └┘      └─────────┘       
src                              └┘                   └────┘             └─────────┘       
typ                              └┘             └────┘   └┘      └─────────┘       
3126  
3127  end choose
3128  
3129  /- Ico -/
3130  
3131  /-- `Ico n m` is the multiset lifted from the list `Ico n m`, e.g. the set `{n, n+1, ..., m-1}`. -/
3132  def Ico (n m : ℕ) : multiset ℕ := Ico n m
id                      └──────┘     └─┘  
src                     └──────┘     └─┘
typ                     └──────┘     └─┘  
doc                      └──────┘      └─┘
3133  
3134  namespace Ico
3135  
3136  theorem map_add (n m k : ℕ) : (Ico n m).map ((+) k) = Ico (n + k) (m + k) :=
id                                 └─┘   └─┘         └─┘         
src                                └─┘     └─┘          └─┘           
typ                                └─┘   └─┘         └─┘         
doc                                 └─┘     └─┘            └─┘
3137  congr_arg coe $ list.Ico.map_add _ _ _
id   └───────┘ └─┘   └──────────────┘
src  └───────┘ └─┘   └──────────────┘
typ  └───────┘ └─┘   └──────────────┘
3138  
3139  theorem map_sub (n m k : ℕ) (h : k ≤ n) : (Ico n m).map (λ x, x - k) = Ico (n - k) (m - k) :=
id                                          └─┘   └─┘            └─┘         
src                                           └─┘     └─┘               └─┘           
typ                                         └─┘   └─┘            └─┘         
doc                                             └─┘     └─┘                 └─┘
3140  congr_arg coe $ list.Ico.map_sub _ _ _ h
id   └───────┘ └─┘   └──────────────┘       
src  └───────┘ └─┘   └──────────────┘
typ  └───────┘ └─┘   └──────────────┘       
3141  
3142  theorem zero_bot (n : ℕ) : Ico 0 n = range n :=
id                             └─┘     └───┘ 
src                            └─┘      └───┘
typ                            └─┘     └───┘ 
doc                             └─┘       └───┘
3143  congr_arg coe $ list.Ico.zero_bot _
id   └───────┘ └─┘   └───────────────┘
src  └───────┘ └─┘   └───────────────┘
typ  └───────┘ └─┘   └───────────────┘
3144  
3145  @[simp] theorem card (n m : ℕ) : (Ico n m).card = m - n :=
id                                    └─┘   └──┘     
src                                   └─┘     └──┘     
typ                                   └─┘   └──┘     
doc    └──┘                            └─┘     └──┘
3146  list.Ico.length _ _
id   └─────────────┘
src  └─────────────┘
typ  └─────────────┘
3147  
3148  theorem nodup (n m : ℕ) : nodup (Ico n m) := Ico.nodup _ _
id                            └───┘  └─┘       └───────┘
src                           └───┘  └─┘         └───────┘
typ                           └───┘  └─┘       └───────┘
doc                            └───┘  └─┘
3149  
3150  @[simp] theorem mem {n m l : ℕ} : l ∈ Ico n m ↔ n ≤ l ∧ l < m :=
id                                      └─┘          
src                                      └─┘              
typ                                     └─┘          
doc    └──┘                                └─┘
3151  list.Ico.mem
id   └──────────┘
src  └──────────┘
typ  └──────────┘
3152  
3153  theorem eq_zero_of_le {n m : ℕ} (h : m ≤ n) : Ico n m = 0 :=
id                                             └─┘   
src                                              └─┘     
typ                                            └─┘   
doc                                                └─┘
3154  congr_arg coe $ list.Ico.eq_nil_of_le h
id   └───────┘ └─┘   └───────────────────┘ 
src  └───────┘ └─┘   └───────────────────┘
typ  └───────┘ └─┘   └───────────────────┘ 
3155  
3156  @[simp] theorem self_eq_zero {n : ℕ} : Ico n n = 0 :=
id                                         └─┘   
src                                        └─┘     
typ                                        └─┘   
doc    └──┘                                 └─┘
3157  eq_zero_of_le $ le_refl n
id   └───────────┘   └─────┘ 
src  └───────────┘   └─────┘
typ  └───────────┘   └─────┘ 
3158  
3159  @[simp] theorem eq_zero_iff {n m : ℕ} : Ico n m = 0 ↔ m ≤ n :=
id                                          └─┘         
src                                         └─┘           
typ                                         └─┘         
doc    └──┘                                  └─┘
3160  iff.trans (coe_eq_zero _) list.Ico.eq_empty_iff
id   └───────┘  └─────────┘    └───────────────────┘
src  └───────┘  └─────────┘    └───────────────────┘
typ  └───────┘  └─────────┘    └───────────────────┘
3161  
3162  lemma add_consecutive {n m l : ℕ} (hnm : n ≤ m) (hml : m ≤ l) :
id                                                        
src                                                         
typ                                                       
3163    Ico n m + Ico m l = Ico n l :=
id     └─┘    └─┘    └─┘  
src    └─┘      └─┘      └─┘
typ    └─┘    └─┘    └─┘  
doc    └─┘       └─┘       └─┘
3164  congr_arg coe $ list.Ico.append_consecutive hnm hml
id   └───────┘ └─┘   └─────────────────────────┘ └─┘ └─┘
src  └───────┘ └─┘   └─────────────────────────┘
typ  └───────┘ └─┘   └─────────────────────────┘ └─┘ └─┘
3165  
3166  @[simp] lemma inter_consecutive (n m l : ℕ) : Ico n m ∩ Ico m l = 0 :=
id                                                └─┘    └─┘   
src                                               └─┘      └─┘     
typ                                               └─┘    └─┘   
doc    └──┘                                        └─┘       └─┘
3167  congr_arg coe $ list.Ico.bag_inter_consecutive n m l
id   └───────┘ └─┘   └────────────────────────────┘   
src  └───────┘ └─┘   └────────────────────────────┘
typ  └───────┘ └─┘   └────────────────────────────┘   
3168  
3169  @[simp] theorem succ_singleton {n : ℕ} : Ico n (n+1) = {n} :=
id                                           └─┘       
src                                          └─┘         
typ                                          └─┘       
doc    └──┘                                   └─┘
3170  congr_arg coe $ list.Ico.succ_singleton
id   └───────┘ └─┘   └─────────────────────┘
src  └───────┘ └─┘   └─────────────────────┘
typ  └───────┘ └─┘   └─────────────────────┘
3171  
3172  theorem succ_top {n m : ℕ} (h : n ≤ m) : Ico n (m + 1) = m :: Ico n m :=
id                                        └─┘          └┘ └─┘  
src                                         └─┘             └┘ └─┘
typ                                       └─┘          └┘ └─┘  
doc                                           └─┘               └┘ └─┘
3173  by rw [Ico, list.Ico.succ_top h, ← coe_add, add_comm]; refl
id          └─┘  └───────────────┘     └─────┘  └──────┘
src     └──┘└─┘└┘└───────────────┘ └──┘└─────┘└┘└──────┘  └────
typ     └──┘└─┘└┘└───────────────┘└──┘└─────┘└┘└──────┘  └────
doc     └──┘└─┘└┘                  └──┘       └┘          └────
txt     └──┘   └┘                  └──┘       └┘          └────
par     └──┘   └┘                  └──┘       └┘          └────
pid       └┘   └┘                  └──┘       └┘              
st     └──────┘└───────────────────┘└─────────┘└────────┘└──────
3174  
src  
typ  
doc  
txt  
par  
pid  
st   
3175  theorem eq_cons {n m : ℕ} (h : n < m) : Ico n m = n :: Ico (n + 1) m :=
id                                       └─┘     └┘ └─┘       
src                                        └─┘        └┘ └─┘    
typ                                      └─┘     └┘ └─┘       
doc                                          └─┘         └┘ └─┘
3176  congr_arg coe $ list.Ico.eq_cons h
id   └───────┘ └─┘   └──────────────┘ 
src  └───────┘ └─┘   └──────────────┘
typ  └───────┘ └─┘   └──────────────┘ 
3177  
3178  @[simp] theorem pred_singleton {m : ℕ} (h : 0 < m) : Ico (m - 1) m = {m - 1} :=
id                                                     └─┘          
src                                                     └─┘             
typ                                                    └─┘          
doc    └──┘                                               └─┘
3179  congr_arg coe $ list.Ico.pred_singleton h
id   └───────┘ └─┘   └─────────────────────┘ 
src  └───────┘ └─┘   └─────────────────────┘
typ  └───────┘ └─┘   └─────────────────────┘ 
3180  
3181  @[simp] theorem not_mem_top {n m : ℕ} : m ∉ Ico n m :=
id                                            └─┘  
src                                            └─┘
typ                                           └─┘  
doc    └──┘                                      └─┘
3182  list.Ico.not_mem_top
id   └──────────────────┘
src  └──────────────────┘
typ  └──────────────────┘
3183  
3184  lemma filter_lt_of_top_le {n m l : ℕ} (hml : m ≤ l) : (Ico n m).filter (λ x, x < l) = Ico n m :=
id                                                      └─┘   └────┘            └─┘  
src                                                       └─┘     └────┘               └─┘
typ                                                     └─┘   └────┘            └─┘  
doc                                                         └─┘     └────┘                 └─┘
3185  congr_arg coe $ list.Ico.filter_lt_of_top_le hml
id   └───────┘ └─┘   └──────────────────────────┘ └─┘
src  └───────┘ └─┘   └──────────────────────────┘
typ  └───────┘ └─┘   └──────────────────────────┘ └─┘
3186  
3187  lemma filter_lt_of_le_bot {n m l : ℕ} (hln : l ≤ n) : (Ico n m).filter (λ x, x < l) = ∅ :=
id                                                      └─┘   └────┘            
src                                                       └─┘     └────┘               
typ                                                     └─┘   └────┘            
doc                                                         └─┘     └────┘
3188  congr_arg coe $ list.Ico.filter_lt_of_le_bot hln
id   └───────┘ └─┘   └──────────────────────────┘ └─┘
src  └───────┘ └─┘   └──────────────────────────┘
typ  └───────┘ └─┘   └──────────────────────────┘ └─┘
3189  
3190  lemma filter_lt_of_ge {n m l : ℕ} (hlm : l ≤ m) : (Ico n m).filter (λ x, x < l) = Ico n l :=
id                                                  └─┘   └────┘            └─┘  
src                                                   └─┘     └────┘               └─┘
typ                                                 └─┘   └────┘            └─┘  
doc                                                     └─┘     └────┘                 └─┘
3191  congr_arg coe $ list.Ico.filter_lt_of_ge hlm
id   └───────┘ └─┘   └──────────────────────┘ └─┘
src  └───────┘ └─┘   └──────────────────────┘
typ  └───────┘ └─┘   └──────────────────────┘ └─┘
3192  
3193  @[simp] lemma filter_lt (n m l : ℕ) : (Ico n m).filter (λ x, x < l) = Ico n (min m l) :=
id                                         └─┘   └────┘            └─┘   └─┘  
src                                        └─┘     └────┘               └─┘    └─┘
typ                                        └─┘   └────┘            └─┘   └─┘  
doc    └──┘                                 └─┘     └────┘                 └─┘
3194  congr_arg coe $ list.Ico.filter_lt n m l
id   └───────┘ └─┘   └────────────────┘   
src  └───────┘ └─┘   └────────────────┘
typ  └───────┘ └─┘   └────────────────┘   
3195  
3196  lemma filter_le_of_le_bot {n m l : ℕ} (hln : l ≤ n) : (Ico n m).filter (λ x, l ≤ x) = Ico n m :=
id                                                      └─┘   └────┘            └─┘  
src                                                       └─┘     └────┘               └─┘
typ                                                     └─┘   └────┘            └─┘  
doc                                                         └─┘     └────┘                 └─┘
3197  congr_arg coe $ list.Ico.filter_le_of_le_bot hln
id   └───────┘ └─┘   └──────────────────────────┘ └─┘
src  └───────┘ └─┘   └──────────────────────────┘
typ  └───────┘ └─┘   └──────────────────────────┘ └─┘
3198  
3199  lemma filter_le_of_top_le {n m l : ℕ} (hml : m ≤ l) : (Ico n m).filter (λ x, l ≤ x) = ∅ :=
id                                                      └─┘   └────┘            
src                                                       └─┘     └────┘               
typ                                                     └─┘   └────┘            
doc                                                         └─┘     └────┘
3200  congr_arg coe $ list.Ico.filter_le_of_top_le hml
id   └───────┘ └─┘   └──────────────────────────┘ └─┘
src  └───────┘ └─┘   └──────────────────────────┘
typ  └───────┘ └─┘   └──────────────────────────┘ └─┘
3201  
3202  lemma filter_le_of_le {n m l : ℕ} (hnl : n ≤ l) : (Ico n m).filter (λ x, l ≤ x) = Ico l m :=
id                                                  └─┘   └────┘            └─┘  
src                                                   └─┘     └────┘               └─┘
typ                                                 └─┘   └────┘            └─┘  
doc                                                     └─┘     └────┘                 └─┘
3203  congr_arg coe $ list.Ico.filter_le_of_le hnl
id   └───────┘ └─┘   └──────────────────────┘ └─┘
src  └───────┘ └─┘   └──────────────────────┘
typ  └───────┘ └─┘   └──────────────────────┘ └─┘
3204  
3205  @[simp] lemma filter_le (n m l : ℕ) : (Ico n m).filter (λ x, l ≤ x) = Ico (max n l) m :=
id                                         └─┘   └────┘            └─┘  └─┘    
src                                        └─┘     └────┘               └─┘  └─┘
typ                                        └─┘   └────┘            └─┘  └─┘    
doc    └──┘                                 └─┘     └────┘                 └─┘
3206  congr_arg coe $ list.Ico.filter_le n m l
id   └───────┘ └─┘   └────────────────┘   
src  └───────┘ └─┘   └────────────────┘
typ  └───────┘ └─┘   └────────────────┘   
3207  
3208  end Ico
3209  
3210  variable (α)
3211  
3212  def subsingleton_equiv [subsingleton α] : list α ≃ multiset α :=
id                           └──────────┘     └──┘   └──────┘ 
src                          └──────────┘      └──┘    └──────┘
typ                          └──────────┘     └──┘   └──────┘ 
doc                                                    └──────┘
3213  { to_fun := coe,
id               └─┘
src              └─┘
typ              └─┘
3214    inv_fun := quot.lift id $ λ (a b : list α) (h : a ~ b),
id                └───────┘ └┘            └──┘          
src                         └┘            └──┘           
typ               └───────┘ └┘            └──┘          
doc                                                      
3215      list.ext_le (perm_length h) $ λ n h₁ h₂, subsingleton.elim _ _,
id       └─────────┘  └─────────┘        └┘ └┘  └───────────────┘
src      └─────────┘  └─────────┘                 └───────────────┘
typ      └─────────┘  └─────────┘        └┘ └┘  └───────────────┘
3216    left_inv := λ l, rfl,
id                     └─┘
src                     └─┘
typ                    └─┘
3217    right_inv := λ m, quot.induction_on m $ λ l, rfl }
id                      └───────────────┘        └─┘
src                      └───────────────┘          └─┘
typ                     └───────────────┘        └─┘
3218  
3219  namespace nat
3220  
3221  /-- The antidiagonal of a natural number `n` is
3222      the multiset of pairs `(i,j)` such that `i+j = n`. -/
3223  def antidiagonal (n : ℕ) : multiset (ℕ × ℕ) :=
id                             └──────┘    
src                            └──────┘    
typ                            └──────┘    
doc                             └──────┘
3224  list.nat.antidiagonal n
id   └───────────────────┘ 
src  └───────────────────┘
typ  └───────────────────┘ 
doc  └───────────────────┘
3225  
3226  /-- A pair (i,j) is contained in the antidiagonal of `n` if and only if `i+j=n`. -/
3227  @[simp] lemma mem_antidiagonal {n : ℕ} {x : ℕ × ℕ} :
id                                                
src                                               
typ                                               
doc    └──┘
3228    x ∈ antidiagonal n ↔ x.1 + x.2 = n :=
id       └──────────┘         
src       └──────────┘           
typ      └──────────┘         
doc        └──────────┘
3229  by rw [antidiagonal, mem_coe, list.nat.mem_antidiagonal]
id          └──────────┘  └─────┘  └───────────────────────┘
src     └──┘└──────────┘└┘└─────┘└┘└───────────────────────┘└─
typ     └──┘└──────────┘└┘└─────┘└┘└───────────────────────┘└─
doc     └──┘└──────────┘└┘       └┘└───────────────────────┘└─
txt     └──┘            └┘       └┘                         └─
par     └──┘            └┘       └┘                         └─
pid       └┘            └┘       └┘                         
st     └───────────────┘└───────┘└─────────────────────────┘
3230  
src  
typ  
doc  
txt  
par  
pid  
st   
3231  /-- The cardinality of the antidiagonal of `n` is `n+1`. -/
3232  @[simp] lemma card_antidiagonal (n : ℕ) : (antidiagonal n).card = n+1 :=
id                                             └──────────┘  └──┘   
src                                            └──────────┘   └──┘    
typ                                            └──────────┘  └──┘   
doc    └──┘                                     └──────────┘   └──┘
3233  by rw [antidiagonal, coe_card, list.nat.length_antidiagonal]
id          └──────────┘  └──────┘  └──────────────────────────┘
src     └──┘└──────────┘└┘└──────┘└┘└──────────────────────────┘└─
typ     └──┘└──────────┘└┘└──────┘└┘└──────────────────────────┘└─
doc     └──┘└──────────┘└┘        └┘└──────────────────────────┘└─
txt     └──┘            └┘        └┘                            └─
par     └──┘            └┘        └┘                            └─
pid       └┘            └┘        └┘                            
st     └───────────────┘└────────┘└────────────────────────────┘
3234  
src  
typ  
doc  
txt  
par  
pid  
st   
3235  /-- The antidiagonal of `0` is the list `[(0,0)]` -/
3236  @[simp] lemma antidiagonal_zero : antidiagonal 0 = {(0, 0)} :=
id                                     └──────────┘    
src                                    └──────────┘    
typ                                    └──────────┘    
doc    └──┘                            └──────────┘
3237  by { rw [antidiagonal, list.nat.antidiagonal_zero], refl }
id            └──────────┘  └────────────────────────┘
src       └──┘└──────────┘└┘└────────────────────────┘  └───┘
typ       └──┘└──────────┘└┘└────────────────────────┘  └───┘
doc       └──┘└──────────┘└┘└────────────────────────┘  └───┘
txt       └──┘            └┘                            └───┘
par       └──┘            └┘                            └───┘
pid         └┘            └┘                                
st     └─────────────────┘└──────────────────────────┘└──────┘└┘
3238  
3239  /-- The antidiagonal of `n` does not contain duplicate entries. -/
3240  lemma nodup_antidiagonal (n : ℕ) : nodup (antidiagonal n) :=
id                                     └───┘  └──────────┘ 
src                                    └───┘  └──────────┘
typ                                    └───┘  └──────────┘ 
doc                                     └───┘  └──────────┘
3241  coe_nodup.2 $ list.nat.nodup_antidiagonal n
id   └───────┘    └─────────────────────────┘ 
src  └───────┘    └─────────────────────────┘
typ  └───────┘    └─────────────────────────┘ 
doc                └─────────────────────────┘
3242  
3243  end nat
3244  
3245  end multiset
3246  
3247  @[to_additive]
doc    └─────────┘
3248  theorem monoid_hom.map_multiset_prod [comm_monoid α] [comm_monoid β] (f : α →* β) (s : multiset α) :
id                                         └─────────┘    └─────────┘         └┘        └──────┘ 
src                                        └─────────┘     └─────────┘           └┘         └──────┘
typ                                        └─────────┘    └─────────┘         └┘        └──────┘ 
doc                                                                              └┘         └──────┘
3249    f s.prod = (s.map f).prod :=
id      └───┘   └──┘  └──┘
src       └───┘    └──┘   └──┘
typ     └───┘   └──┘  └──┘
doc       └───┘     └──┘   └──┘
3250  (s.prod_hom f).symm
id    └───────┘  └──┘
src    └───────┘   └──┘
typ   └───────┘  └──┘